该系列文章总纲链接:专题分纲目录 android 系统核心机制 binder
本章关键点总结 & 说明:
这里专注于Binder C++部分的TestClient 分析 部分即可,仅有两个关键点。针对获取服务和使用服务。
一个Client想要得到某个service的信息,需要先和service_manager通信,调用getService获取service信息。(实际上这是对一般常见的非匿名service才采用的策略,对于匿名service是不需要获取服务的)
这里以之前的TestClient客户端测试代码来进行分析,如下所示:
#define LOG_TAG "TestService"
//...
#include "IHelloService.h"
using namespace android;
/* ./test_client <hello>
* ./test_client <readfile>
* ./test_client <hello> <name>
*/
int main(int argc, char **argv)
{
int cnt;
if (argc < 2){
ALOGI("Usage:\n");
ALOGI("%s <readfile>\n", argv[0]);
ALOGI("%s <hello|goodbye>\n", argv[0]);
ALOGI("%s <hello|goodbye> <name>\n", argv[0]);
return -1;
}
/* getService */
/* 打开驱动, mmap */
sp<ProcessState> proc(ProcessState::self()); //关键点1
/* 获得BpServiceManager */
sp<IServiceManager> sm = defaultServiceManager();//关键点2
if (strcmp(argv[1], "hello") == 0)
{
sp<IBinder> binder = sm->getService(String16("hello"));//关键点3
if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}
// service肯定是BpHelloServie指针 ,关键点4
sp<IHelloService> service = interface_cast<IHelloService>(binder);
/* 调用Service的函数 */
if (argc < 3) {
service->sayhello();//关键点5
ALOGI("client call sayhello");
}
else {
cnt = service->sayhello_to(argv[2]);
ALOGI("client call sayhello_to, cnt = %d", cnt);
}
}
else if (strcmp(argv[1], "readfile") == 0)
{
//...
}
return 0;
}
上面的代码中 对于关键点 ,我们进行了标注,同时,因为 关键点1 、关键点2、关键点4在之前的博文binder TestServer中已经分析过,因此在这里 主要分析 关键点3,因为关键点5 功能点仅为测试。
1 获取服务 流程分析
这里,通过getService获取binder对象,代码实现如下所示:
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
}
这里通过checkService来获取binder对象,代码实现如下所示:
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发送请求,自后通过reply来获取binder对象。如果要使用返回的BpHelloService获取业务函数,均需要把请求数据打包发送给binder驱动,并且由BpBinder中的handle值找到对应的处理者来处理,处理过程为:@1 通信层收到请求,@2 递交给业务层处理
HelloService中有2个线程在talkWithDriver,假设其中一个线程收到请求消息,会通过之前的executeCommand调用来处理该请求,代码实现如下所示:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
...
switch (cmd) {
case BR_ERROR:
...
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(result == NO_ERROR,"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
set_sched_policy(mMyThreadId, SP_BACKGROUND);
}
}
Parcel reply;
if (tr.target.ptr) {
/* BnServiceXXX从BBiner派生,这里的b是实现BnServiceXXX的对象,即直接定位业务层对象 */
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
} else {
/* the_context_object是IPCThreadState中的一个全局变量,
可以通过setTheContextObject函数来设置 */
const status_t error = the_context_object->transact
(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
if ((tr.flags & TF_ONE_WAY) == 0) {
sendReply(reply, 0);
}
mCallingPid = origPid;
mCallingUid = origUid;
}
break;
...
return result;
}
2 onTransact函数
BnHelloService实现了onTransact函数,它根据code调用对应业务逻辑方法。业务逻辑由HelloService来实现的,BnHelloService是继承BBinder的,因此,调用BnHelloService的transact方法,实际上就是调用BBinder的transact方法BBinder的传输代码分析如下所示:
status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
/* 调用子类的onTransact,这是一个虚函数 */
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
这里的onTransact方法实际上是调用子类的,分析BnHelloService的关键方法onTransact,实现如下所示:
status_t BnHelloService::onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags)
{
switch (code) {
case HELLO_SVR_CMD_SAYHELLO: {
sayhello();
reply->writeInt32(0); /* no exception */
return NO_ERROR;
} break;
case HELLO_SVR_CMD_SAYHELLO_TO: {
//@1 读取传入参数,并转换
int32_t policy = data.readInt32();
String16 name16_tmp = data.readString16(); /* IHelloService */
String16 name16 = data.readString16();
String8 name8(name16);
//@2 调用对应函数
int cnt = sayhello_to(name8.string());
//@3 返回值转换,并发送
reply->writeInt32(0); /* no exception */
reply->writeInt32(cnt);
return NO_ERROR;
} break;
//...
default:
return BBinder::onTransact(code, data, reply, flags);
}
这两个流程均为客户端的操作,先是获取servicemanager,通过servicemanager获取HelloService的,通过HelloService获取对应的方法;一个是获取服务的流程,而另一个是使用服务的流程。