Binder学习笔记(三)—— binder客户端是如何组织checkService数据的
起点从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数据的的更多相关文章
- Binder学习笔记(五)—— Parcel是怎么打包数据的?
前文中曾经遇到过Parcel,从命名上知道他负责数据打包.在checkService的请求/响应体系中,Parcel只打包了基本数据类型,如Int32.String16……后面还要用于打包抽象数据类型 ...
- Binder学习笔记(四)—— ServiceManager如何响应checkService请求
这要从frameworks/native/cmds/servicemanager/service_manager.c:347的main函数说起,该文件编译后生成servicemanager. int ...
- scrapy学习笔记(三):使用item与pipeline保存数据
scrapy下使用item才是正经方法.在item中定义需要保存的内容,然后在pipeline处理item,爬虫流程就成了这样: 抓取 --> 按item规则收集需要数据 -->使用pip ...
- Binder学习笔记(八)—— 客户端如何组织Test()请求 ?
还从客户端代码看起TestClient.cpp:14 int main() { sp < IServiceManager > sm = defaultServiceManager(); / ...
- Binder学习笔记(六)—— binder服务端是如何组织addService数据的
在checkService的调查中我们知道客户端向ServiceManager请求服务名,ServiceManager根据服务名遍历本地链表,找到匹配的handle返回给客户端.这个handle显然是 ...
- Binder学习笔记(九)—— 服务端如何响应Test()请求 ?
从服务端代码出发,TestServer.cpp int main() { sp < ProcessState > proc(ProcessState::self()); sp < I ...
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...
- 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记
回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...
- ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心
作者:Grey 原文地址:ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 很多程序往 ...
随机推荐
- 【HTML代码】访问页面时,拨打页面中的电话号码
这两天在写HTML页面今天要实现一个手机用户访问页面的时候,如果页面中有电话号码,点击可以打电话或者是发信息,之前没做过今天刚听说感觉很高大上会很难,实际上简单的让我内牛满面啊,, 小婊砸 (* ...
- QtCreator开启-O编译优化的方式
首先,编译优化必须是在Release模式下进行,保证程序没有任何bug的条件下进行执行.编译优化能极大提升程序的运行效率,级别越高速度越快,但是对代码健壮性要求也越高! 选择编译release模式,在 ...
- HDU5469(树的dfs)
Antonidas Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- FLASH和EEROM使用【转】
最近在看代码的时候,遇到了一个使用FLASH模拟EEPROM的情况,看到这个我当时是一脸蒙蔽啊,对于一个有时候连FLASH和EEPROM都分不清的人来说,怎么可能读懂用FLASH来模拟EEPROM呢? ...
- spring--AOP--权限---demo1---bai
AOP权限DEMO1: 实体类: package com.etc.entity; import org.aspectj.lang.annotation.Pointcut; public class U ...
- CreateThread demo
#include "stdafx.h"#include<windows.h>#include<strsafe.h>//win2003SDK必须安装 要不无此 ...
- Java堆初始大小的建议值
摘自:<Java Performance>第三章 Initial Heap Space Size Configuration This section describes how to u ...
- ConfigureAwait(false)
昨天在做项目的时候,用的dapper查数据用的QueryAsync 异步方法.给上级做代码审核时,上级说最好加上ConfigureAwait(false).能减少一些性能开销. 因为之前没用过所以看了 ...
- nginx 限制solr
server { listen 80; server_name bai.com www.bai.com; location /solr/ { allow 192.168.0.0/24; allow ...
- hadoop-eclipse-plugin-2.6.0-cdh5.4.0 插件编译
1.JDK配置 1) 安装jdk 2) 配置环境变量 JAVA_HOME.CLASSPATH.PATH等设置 2.Eclipse 1).下载eclipse-jee-juno-SR2.rar 2).解压 ...