前面讲了如何定义个native(C++)层的service,TestService,接下里我们继续完善,讲一下如何将它注册到servicemanager,成为全局的service。
TestService.h
#ifndef ANDROID_HXIONFG_TEST_H
#define ANDROID_HXIONFG_TEST_H
#include <ITestService.h>
#include <binder/BinderService.h>
namespace android {
class TestService : public BnTestService, public BinderService<TestService> {
public:
TestService();
virtual ~TestService();
// Implementation of BinderService<T>
static char const* getServiceName() { return "hxiong.test"; }
virtual status_t test(int api);
};
}
#endif
然后再写一个可执行程序,将它编译成可执行程序文件
main_testserver.cpp
#include "TestService.h"
using namespace android;
int main(int argc __unused, char** argv __unused)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
TestService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
1、ProcessState::self()
创建ProcessState 实例,注意这是一个单例,也就是一个进程中只有一个ProcessState 实例,ProcessState在构造函数中做了一件十分重要的事,那就是打开binder driver。返回fd,后面就可以通过这个fd和binder driver打交道了,跟driver打交道,基本上用的都是ioctl。static int open_driver()
{
int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}
2、TestService::instantiate()
这个会调用BinderService 的instantiate()函数,主要作用就是将TestService注册到ServiceManager里面,成为一个全局的service,service的名字如上面定义的"hxiong.test"。
rameworks/native/include/binder/BinderService.h
template<typename SERVICE>
class BinderService{
//在这里模版中的SERVICE 就是TestService类,所以publish里面创建了TestService的实例
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
static void instantiate() { publish(); }
}
3、ProcessState::self()->startThreadPool()
创建启动线程池
4、IPCThreadState::self()->joinThreadPool();
IPCThreadState也是单例模式,一个进程中只有一个IPCThreadState实例,joinThreadPool ()的作用就是通过ioctl从binder driver读是数据,然后处理数据。
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
5、binder的server 端如何处理请求
调用IPCThreadState::joinThreadPool()后,就是让当前的线程(也就是我们常说的binder线程)等待client端发起的通信。
1)IPCThreadState::takeWithDriver()
这个可以当作是binder线程在调用revc,接收来自binderdriver返回的数据,binder线程会阻塞在这里。可以通过打印线程的调用栈就知道,连接adb 后,输入如下命令
C:\Users\hxiong>adb root
C:\Users\hxiong>adb shell
generic_x86_64:/ # ps | grep cameraserver
cameraserver 1292 1 21240 5788 binder_thr 00ffffe430 S /system/bin/camera
server
generic_x86_64:/ # debuggerd -b 1292
Sending request to dump task 1292.
----- pid 1292 at 2017-06-16 14:14:44 -----
Cmd line: /system/bin/cameraserver
ABI: 'x86'
"cameraserver" sysTid=1292
#00 pc ffffe430 [vdso:ffffe000] (__kernel_vsyscall+16)
#01 pc 0008a07c /system/lib/libc.so (__ioctl+28)
#02 pc 000251f1 /system/lib/libc.so (ioctl+42)
#03 pc 000477e7 /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
#04 pc 0004799a /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
#05 pc 0004826f /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
#06 pc 00000950 /system/bin/cameraserver
#07 pc 00016bd6 /system/lib/libc.so (__libc_init+100)
#08 pc 000007c2 /system/bin/cameraserver
"EmulatedCameraH" sysTid=1311
#00 pc ffffe430 [vdso:ffffe000] (__kernel_vsyscall+16)
#01 pc 0008b9ac /system/lib/libc.so (read+28)
#02 pc 00099880 /system/lib/libc.so (__read_chk+74)
#03 pc 00019bb1 /system/lib/hw/camera.ranchu.so (_ZN7android27EmulatedCameraHotplugThread10threadLoopEv+625)
#04 pc 00012095 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
#05 pc 00011883 /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
#06 pc 00086cdf /system/lib/libc.so (_ZL15__pthread_startPv+190)
#07 pc 00022f00 /system/lib/libc.so (__start_thread+25)
#08 pc 00020766 /system/lib/libc.so (__bionic_clone+70)
"Binder:1292_1" sysTid=1574
#00 pc ffffe430 [vdso:ffffe000] (__kernel_vsyscall+16)
#01 pc 0008a07c /system/lib/libc.so (__ioctl+28)
#02 pc 000251f1 /system/lib/libc.so (ioctl+42)
#03 pc 000477e7 /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
#04 pc 0004799a /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
#05 pc 0004826f /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
#06 pc 0006edbe /system/lib/libbinder.so (_ZN7android10PoolThread10threadLoopEv+46)
#07 pc 00012095 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
#08 pc 00011883 /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
#09 pc 00086cdf /system/lib/libc.so (_ZL15__pthread_startPv+190)
#10 pc 00022f00 /system/lib/libc.so (__start_thread+25)
#11 pc 00020766 /system/lib/libc.so (__bionic_clone+70)
"Binder:1292_2" sysTid=2167
#00 pc ffffe430 [vdso:ffffe000] (__kernel_vsyscall+16)
#01 pc 0008a07c /system/lib/libc.so (__ioctl+28)
#02 pc 000251f1 /system/lib/libc.so (ioctl+42)
#03 pc 000477e7 /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
#04 pc 0004799a /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
#05 pc 0004826f /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
#06 pc 0006edbe /system/lib/libbinder.so (_ZN7android10PoolThread10threadLoopEv+46)
#07 pc 00012095 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
#08 pc 00011883 /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
#09 pc 00086cdf /system/lib/libc.so (_ZL15__pthread_startPv+190)
#10 pc 00022f00 /system/lib/libc.so (__start_thread+25)
#11 pc 00020766 /system/lib/libc.so (__bionic_clone+70)
----- end 1292 -----
generic_x86_64:/ #
通过上面的打印也看到了,binder线程会一直“阻塞”在takeWithDriver
2)IPCThreadState::executeCommand()
这个函数用于处理binder driver返回的数据,如果只考虑service端的处理,我们只需要看如下代码就可以了。
IPCThreadState::executeCommand()
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 binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
// We have inherited a reduced priority from the caller, but do not
// want to run in that state in this process. The driver set our
// priority already (though not our scheduling class), so bounce
// it back to the default before invoking the transaction.
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
// We want to use the inherited priority from the caller.
// Ensure this thread is in the background scheduling class,
// since the driver won't modify scheduling classes for us.
// The scheduling group is reset to default by the caller
// once this method returns after the transaction is complete.
set_sched_policy(mMyThreadId, SP_BACKGROUND);
}
}
//ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
Parcel reply;
status_t error;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_TRANSACTION thr " << (void*)pthread_self()
<< " / obj " << tr.target.ptr << " / code "
<< TypeCode(tr.code) << ": " << indent << buffer
<< dedent << endl
<< "Data addr = "
<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
<< ", offsets addr="
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
//ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid);
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
mCallingPid = origPid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
}
}
break;
其实我们只要关心下面这段代码就够了
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>( tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags); //很关键的这一行
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);
这一行是怎么调到TestService 里面去的呢,注意(tr.cookie)其实就指向了TestService,我们在publish 注册这个service的时候,创建了这个实例。
不好意思,我又把这个图贴出来了,因为这个继承关键很重要,一定要看懂才行,不然会被绕晕的。
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);
这段代码会调到 BBinder::transact(),然后调用onTransact()
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:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
因为子类有重写onTransact(),所以会调用到BnTestService::onTransact()
status_t BnTestService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case TEST: {
CHECK_INTERFACE(ITestService, data, reply);
int api = data.readInt32();
int result=test(api); //这里会调用到TestService 的test函数
reply->writeInt32(result);
return NO_ERROR;
}
}
return BBinder::onTransact(code, data, reply, flags);
}
最后通过switch case 确定调用TestService 对应的函数。
---------------------------------------------------------------------------------------------------------------------------------------------------
分析完毕,欢迎评论...