还从客户端代码看起TestClient.cpp:14

int main() {
sp < IServiceManager > sm = defaultServiceManager(); // new BpServiceManager(new BpBinder(0));
sp < IBinder > binder = sm->getService(String16("service.testservice")); //
sp<ITestService> cs = interface_cast < ITestService > (binder);
cs->test();
return 0;
}

sm->getService(...)返回了什么?

其中第2行defaultServiceManager()返回的是new BpServiceManager(new BpBinder(0));这在《 defaultServiceManager()返回了什么?》中有分析。

接下来的sm->getService(...)《ServiceManager如何响应checkService请求》的结尾给出了ServiceManager响应checkService返回的数据,我们再进入BpServiceManager::getService(...)

frameworks/native/libs/binder/IServiceManager.cpp:134

    virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name); // 调用下面的checkService(...)
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
} virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder(); // 在这里读取了ServiceManager返回的数据
}

进入Parcel::readStrongBinder(),frameworks/native/libs/binder/Parcel.cpp:1334

sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}

进入Parcel::unflatten_binder(...),frameworks/native/libe/binder/Parcel.cpp:293

status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false); if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}

我们看服务端返回的数据:



返回的flat_binder_object的type是BINDER_TYPE_HANDLE,于是进入ProcessState::getStrongProxyForHandle(...),frameworks/native/libs/binder/ProcessState.cpp:179

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) {
......
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) { // 显然handle是0,因为0是ServiceManager
......
} b = new BpBinder(handle); // 走到这里
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
......
result.force_set(b);
e->refs->decWeak(this);
}
} return result;
}

首次执行,会创建一个新的BpBinder(handle),并缓存该节点;以后在被调用,就直接返回该节点了。Parcel::finish_unflatten_binder(...)内部没有任何调用,直接返回了。

因此客户端的getService(...)调用就返回了new BpBinder(handle);其中handle是有服务端在addService时生成(见《binder服务端是如何组织addService数据的?》尾部的addService组织的请求数据图),并由ServiceManager缓存的,binder_uintptr_t值。

interface_cast < ITestService> (binder)返回了什么?

这个函数定义在frameworks/natvie/include/binder/IInterface.h:41

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}

代入模板参数:

inline sp<ITestService> interface_cast(const sp<IBinder>& obj)
{
return ITestService::asInterface(obj);
}

再来看ITestService的定义,Test.h

    class ITestService : public IInterface
{
public:
DECLARE_META_INTERFACE(TestService);
virtual void test()=0;
};

宏DECLARE_META_INTERFACE定义在frameworks/native/include/binder/IInterface.h:74,展开为:

    class ITestService : public IInterface
{
public:
static const android::String16 descriptor;
static android::sp<ITestService> asInterface(
const android::sp<android::IBinder>& obj);
virtual const android::String16& getInterfaceDescriptor() const;
ITestService();
virtual ~ITestService(); virtual void test()=0;
};

在ITestService.cpp中只有这么一行:

IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService");

展开后为:

    const android::String16 ITestService::descriptor("android.TestServer.ITestService");
const android::String16& ITestService::getInterfaceDescriptor() const {
return ITestService::descriptor;
}
android::sp< ITestService > ITestService::asInterface(
const android::sp<android::IBinder>& obj)
{ // obj就是在main函数中传入的binder,即 new BpBinder(handle)
android::sp< ITestService > intr;
if (obj != NULL) {
intr = static_cast< ITestService *>(
obj->queryLocalInterface(ITestService::descriptor).get());
if (intr == NULL) {
intr = new BpTestService(obj);
}
}
return intr;
}
ITestService::ITestService() { }
ITestService::~ITestService() { }

BpBinder::queryLocalInterface(...)这个函数继承自基类IBinder,它直接返回NULL

sp<IInterface>  IBinder::queryLocalInterface(const String16& /*descriptor*/)
{
return NULL;
}

因此ITestService::asInterface(...)就返回了new BpTestService(new BpBinder(handle));即:

interface_cast < ITestService > (binder)返回

new BpTestService(new BpBinder(handle));

进入cs->test()

即BpTestService::test(),TestClient.cpp

void BpTestService::test() {
printf("BpTestService::test()\n");
Parcel data, reply;
data.writeInterfaceToken(ITestService::getInterfaceDescriptor());
remote()->transact(TEST, data, &reply);
printf("reply: %d\n", reply.readInt32());
}

他的remote()是什么?在《defaultServiceManager()返回了什么?》中遇到过BpInterface::remote(),它返回的是在构造函数中传入的Binder。BpTestService正是继承自BpInterface:

class BpTestService: public BpInterface<ITestService>

所以BpTestService的remote()就返回构造时传入的new BpBinder(handle)

《binder客户端是如何组织checkService数据的 ?》中曾分析过,BpBinder::transact(...)调用了IPCThreadState::transact(...)

frameworks/native/libs/binder/IPCThreadState.cpp:548

status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{ // code=TEST, flags=0
status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; ...... err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
...... return err;
}

进入waitForResponse(...),frameworks/native/libs/binder/IPCThreadState.cpp:904

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{ // cmd=BC_TRANSACTION, code=TEST, binderFlags=TF_ACCEPT_FDS
binder_transaction_data tr; tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0; ......
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
...... mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr)); return NO_ERROR;
}

又是一个binder_transaction_data数据包,不过这块数据很简单,内容如下:



TEST定义在Test.h中:

    enum
{
TEST = IBinder::FIRST_CALL_TRANSACTION,
};

它为每一个Binder接口定义一个枚举数字。

  • 轮廓渐渐清晰了:服务端通过addService向ServiceManager注册服务,后者记录下service name和服务实体(实体是什么以后再讨论)。客户端通过getService接口向ServiceManager请求获取到符合指定名称的service。之后调用service的服务接口只不过是向service发送一个数据包,该数据包中包含了指定的服务接口的序列号及参数,具体服务执行是由服务端收到该数据包后完成。
  • 客户端通过getService获得service之后,客户端请求服务就直接发往service,而不再经过ServiceManager。因为上文cs->test()内调用的是new BpInterface(handle)的transact(...)函数,而不再是BpBinder(0)::transact(...),在最终组成的binder_transaction_data包中,handle也是服务端注册在ServiceManager的handle了。

因此,下一步就应该去到服务端,看它是怎么响应test()请求的。

Binder学习笔记(八)—— 客户端如何组织Test()请求 ?的更多相关文章

  1. Binder学习笔记(十二)—— binder_transaction(...)都干了什么?

    binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...

  2. Binder学习笔记(九)—— 服务端如何响应Test()请求 ?

    从服务端代码出发,TestServer.cpp int main() { sp < ProcessState > proc(ProcessState::self()); sp < I ...

  3. Binder学习笔记(五)—— Parcel是怎么打包数据的?

    前文中曾经遇到过Parcel,从命名上知道他负责数据打包.在checkService的请求/响应体系中,Parcel只打包了基本数据类型,如Int32.String16……后面还要用于打包抽象数据类型 ...

  4. Mina框架的学习笔记——Android客户端的实现

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

  5. Redis学习笔记八:集群模式

    作者:Grey 原文地址:Redis学习笔记八:集群模式 前面提到的Redis学习笔记七:主从复制和哨兵只能解决Redis的单点压力大和单点故障问题,接下来要讲的Redis Cluster模式,主要是 ...

  6. Java IO学习笔记八:Netty入门

    作者:Grey 原文地址:Java IO学习笔记八:Netty入门 多路复用多线程方式还是有点麻烦,Netty帮我们做了封装,大大简化了编码的复杂度,接下来熟悉一下netty的基本使用. Netty+ ...

  7. Learning ROS forRobotics Programming Second Edition学习笔记(八)indigo rviz gazebo

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS forRobotics Pro ...

  8. python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑

    python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑 许多人在安装Python第三方库的时候, 经常会为一个问题困扰:到底应该下载什么格式的文件?当我们点开下载页时, 一般 ...

  9. Go语言学习笔记八: 数组

    Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...

  10. 【opencv学习笔记八】创建TrackBar轨迹条

    createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便.首先大家要记住,它往往会和一个回调函数配合起来使用.先看下他的函数 ...

随机推荐

  1. 自定义mysql函数时报错,[Err] 1418 - This function has none of DETERMINISTIC......

    今天在我执行自定义mysql函数的SQL时发生了错误,SQL如下: /** 自定义mysql函数 getChildList */delimiter //CREATE FUNCTION `pengwif ...

  2. C# Chat曲线图,在发布之后出现错误 Invalid temp directory in chart handler configuration c:\TempImageFiles\

    First error message: Invalid temp directory in chart handler configuration c:\TempImageFiles\ Soluti ...

  3. ps命令,性能监控,grep命令

    Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信 ...

  4. demo1 spark streaming 接收 kafka 数据java代码WordCount示例

    1. 首先启动zookeeper windows上的安装见zk 02之 Windows安装和使用zookeeper 启动后见: 2. 启动kafka windows的安装kafka见Windows上搭 ...

  5. codeforce 510C Fox And Names(拓扑排序)

    Fox And Names time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  6. AngularJS:API

    ylbtech-AngularJS:API 1.返回顶部 1. AngularJS API API 意为 Application Programming Interface(应用程序编程接口). An ...

  7. appium-unittest框架中的断言

    1.首先unittest本身是一个python的测试框架,他有他自己的使用规则: 2.如果用其中的方法,需要引入,方法: import unittest class Login(unittest.Te ...

  8. 重新认识synchronized(下)

    synchronized既保证原子性,又保证内存可见性,是一种线程同步的方式,是锁机制的一种java实现.synchronized的实现基于JVM底层,JVM是基于monitor实现的,而monito ...

  9. virtualbox下安装的纯净版centOS7,无法访问外网

    virtualbox下安装的纯净版centOS7,网络设置如下: 需要在/etc/sysconfig/network-scripts/下编辑ifcfg-enp0s3,其中,NOBOOT设置成也是,就可 ...

  10. spring的配置文件在web.xml中加载的方式

    web.xml加载spring配置文件的方式主要依据该配置文件的名称和存放的位置不同来区别,目前主要有两种方式. 1.如果spring配置文件的名称为applicationContext.xml,并且 ...