Binder学习笔记(八)—— 客户端如何组织Test()请求 ?
还从客户端代码看起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()请求 ?的更多相关文章
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...
- Binder学习笔记(九)—— 服务端如何响应Test()请求 ?
从服务端代码出发,TestServer.cpp int main() { sp < ProcessState > proc(ProcessState::self()); sp < I ...
- Binder学习笔记(五)—— Parcel是怎么打包数据的?
前文中曾经遇到过Parcel,从命名上知道他负责数据打包.在checkService的请求/响应体系中,Parcel只打包了基本数据类型,如Int32.String16……后面还要用于打包抽象数据类型 ...
- Mina框架的学习笔记——Android客户端的实现
Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...
- Redis学习笔记八:集群模式
作者:Grey 原文地址:Redis学习笔记八:集群模式 前面提到的Redis学习笔记七:主从复制和哨兵只能解决Redis的单点压力大和单点故障问题,接下来要讲的Redis Cluster模式,主要是 ...
- Java IO学习笔记八:Netty入门
作者:Grey 原文地址:Java IO学习笔记八:Netty入门 多路复用多线程方式还是有点麻烦,Netty帮我们做了封装,大大简化了编码的复杂度,接下来熟悉一下netty的基本使用. Netty+ ...
- Learning ROS forRobotics Programming Second Edition学习笔记(八)indigo rviz gazebo
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS forRobotics Pro ...
- python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑
python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑 许多人在安装Python第三方库的时候, 经常会为一个问题困扰:到底应该下载什么格式的文件?当我们点开下载页时, 一般 ...
- Go语言学习笔记八: 数组
Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...
- 【opencv学习笔记八】创建TrackBar轨迹条
createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便.首先大家要记住,它往往会和一个回调函数配合起来使用.先看下他的函数 ...
随机推荐
- CUDA Pro Tip: Optimized Filtering with Warp-Aggregated Atomics
In this post, I’ll introduce warp-aggregated atomics, a useful technique to improve performance when ...
- Spring学习十一
一: 创建bean的方法: 1: 如果不采用构造注入:默认调用bean的无参构造函数,因此该类必须要提供无参构造函数,用无参构造函数用反射创建bean. : 如果采用构造 ...
- NAND FLASH 驱动分析
NAND FLASH是一个存储芯片 那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A" 问1. 原理图上NAND FLASH和S3C2440之间只有数据线, ...
- linux环境下Apache+Tomcat集群配置
写在前面 apache配置多个tomcat,实现请求分流,多个tomcat服务均衡负载,增加服务的可靠性.最近研究了一下,遇到许多问题,记录一下,方便以后查阅,不喜欢apache,nginx也是可以做 ...
- C语言学习笔记--数组参数和指针参数
1. 数组参数退化为指针的意义 (1)C 语言中只会以值拷贝的方式传递参数,当向函数传递数组时,将整个数组拷贝一份传入函数导致执行效率低下,C 语言以高效作是最初的设计目标,所以这种方法是不可取的. ...
- spring整合mybatis的事物管理配置
一.基本配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:/ ...
- python+requests+excel 接口测试
1.EXCEL文件接口保存方式,如图. 2.然后就是读取EXCEL文件中的数据方法,如下: import xlrd class readExcel(object): def __init__(self ...
- python爬虫(6)--Requests库的用法
1.安装 利用pip来安装reques库,进入pip的下载位置,打开cmd,默认地址为 C:\Python27\Scripts 可以看到文件中有pip.exe,直接在上面输入cmd回车,进入命令行界面 ...
- 在Linux下adb连接不上android手机的终极解决方案
转自: http://blog.csdn.net/liuqz2009/article/details/7942569 1.做android开发的过程,碰到了Linux下adb识别不了android设备 ...
- java虚拟机垃圾回收机制详解
首先,看一下java虚拟机运行的时候内存分配图: jvm虚拟机栈:一个是线程独有的,每次启动一个线程,就创建一个jvm虚拟机栈,线程退出的时候就销毁.这里面主要保存线程本地变量名和局部变量值. 本地方 ...