起点从TestClient.cpp的main函数发起:

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

前文已经分析过sm是new BpServiceManager(new BpBinder(0)),于是sm->getService(…)的行为应该找BpServiceManager::getService(…),frameworks/native/libs/binder/IserviceManager.cpp:134

    virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = ; n < ; n++){
sp<IBinder> svc = checkService(name); // 这里是关键代码
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep();
}
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();
}

BpServiceManager::remote()返回的就是成员变量mRemote,前文也分析过了,也即是new BpBinder(0)。因此remote()->transact(…)调用的是BpBinder::transact(…),

frameworks/native/libs/binder/BpBinder.cpp:159

status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{ // code=CHECK_SERVICE_TRANSACTION, flags=0
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = ;
return status;
} return DEAD_OBJECT;
}

IPCThreadState::self()从命名上来看应该又是个工厂类(前文遇到的ProcessState就是这么命名的),它是个线程单体,每线程一份。具体实现暂且不表,因为在当前上下文中其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)
{ // handle=0, code=CHECK_SERVICE_TRANSACTION, flags=0
status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
} if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
} if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
} if ((flags & TF_ONE_WAY) == ) {
#if 0
if (code == ) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) { // 在checkService(…)传入了非空的reply参数
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == ) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
} return err;
}

这么长一大段,关键代码只有两行,从命名上来看就是一次请求和接收应答的过程。我们先研究请求数据。

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, binderFlags=TF_ACCEPT_FDS, handle=0,
// code=CHECK_SERVICE_TRANSACTION,
binder_transaction_data tr; tr.target.ptr = ; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = ;
tr.sender_pid = ;
tr.sender_euid = ;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
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();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = ;
tr.data.ptr.offsets = ;
} else {
return (mLastError = err);
} mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}

该函数就是把一堆参数组装进binder_transaction_data结构体,并写进mOut。其中data是在checkService(…)中组装的Parcel数据:

data.ipcObjectsCount()*sizeof(binder_size_t)以及data.ipcObjects()分别是什么呢?从命名上来看,他应该是指保存在data中的抽象数据类型的数据,显然在组织checkService时的Parcel数据中是没有抽象数据类型的,可以先不深究它。

Binder学习笔记(三)—— binder客户端是如何组织checkService数据的的更多相关文章

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

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

  2. Binder学习笔记(四)—— ServiceManager如何响应checkService请求

    这要从frameworks/native/cmds/servicemanager/service_manager.c:347的main函数说起,该文件编译后生成servicemanager. int ...

  3. scrapy学习笔记(三):使用item与pipeline保存数据

    scrapy下使用item才是正经方法.在item中定义需要保存的内容,然后在pipeline处理item,爬虫流程就成了这样: 抓取 --> 按item规则收集需要数据 -->使用pip ...

  4. Binder学习笔记(八)—— 客户端如何组织Test()请求 ?

    还从客户端代码看起TestClient.cpp:14 int main() { sp < IServiceManager > sm = defaultServiceManager(); / ...

  5. Binder学习笔记(六)—— binder服务端是如何组织addService数据的

    在checkService的调查中我们知道客户端向ServiceManager请求服务名,ServiceManager根据服务名遍历本地链表,找到匹配的handle返回给客户端.这个handle显然是 ...

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

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

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

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

  8. 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记

    回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...

  9. ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心

    作者:Grey 原文地址:ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 很多程序往 ...

随机推荐

  1. popd命令

    popd命令用于删除目录栈中的记录:如果popd命令不加任何参数,则会先删除目录栈最上面的记录,然后切换到删除过后的目录栈中的最上面的目录. 语法 pushd(选项)(参数) 选项 +N:将第N个目录 ...

  2. MySQL 更新失效

    create table t(id int not null PRIMARY key,c int default null) engine=innodb;insert into t(id,c)valu ...

  3. 2016.9.9《Oracle查询优化改写技巧与案例》电子工业出版社一书中的技巧

    1.coalesce (c1,c2,c3,c4,...) 类似于nvl但可以从多个表达式中返回第一个不是null的值 2.要在where条件中引用列的别名,可以再嵌套一层查询 select * fro ...

  4. IIS安装与部署,站点的部署与配置

    第一章:IIS安装与部署 一,服务器概念的理解: 将设计好的软件只要部署到一台机器(服务器--->IIS)上,其它的员工通过浏览器(网址.)来进行访问. 做好的网站必须部署到这台机器上的IIS中 ...

  5. 搭建node.js

    #node.js:概念介绍及安装 # python服务器.php ->aphche.java ->tomcat. iis # 它是一个可以运行JAVASCRIPTR 的运行环境 # 它可以 ...

  6. select 动态添加option函数

    转自:https://lym6520.iteye.com/blog/309937 经常会用到select动态添加元素,写了个方法,方便调用!  ... /** * 功能:select对象动态添加Opt ...

  7. 【Android 多媒体应用】使用 TTS

    import java.util.Locale; import android.app.Activity; import android.os.Bundle; import android.speec ...

  8. opengl版本和扩展

    检查自己的OpenGL版本 可以很容易的知道自己系统中的OpenGL版本,方法就是调用glGetString函数. const char* version = (const char*)glGetSt ...

  9. SpringBoot12 QueryDSL02之利用QueryDSL实现多表关联查询

    1 业务需求 有的系统业务逻辑比较复杂,存在着多表关联查询的的情况,查询的内容不仅仅是单张表的的内容而是多张表的字段组合而成的,直接使用SplringDataJPA实现是比较复杂的,但是如果使用Que ...

  10. Opengl创建机器人手臂代码示例

    /*******************************************************robot.cpp*基于opengl的机械手臂示例代码*s:机械臂逆时针旋转*S:机械臂 ...