Android : 跟我学Binder --- (5) C++实现
目录:
-
Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制?
-
Android : 跟我学Binder --- (2) AIDL分析及手动实现
-
Android : 跟我学Binder --- (3) C程序示例
-
Android : 跟我学Binder --- (4) 驱动情景分析
-
Android : 跟我学Binder --- (5) C++实现
-
Android : 跟我学Binder --- (6) JAVA实现
一、程序实现
参考文件:
frameworks\av\include\media\IMediaPlayerService.h (IMediaPlayerService,BnMediaPlayerService)
frameworks\av\media\libmedia\IMediaPlayerService.cpp (BpMediaPlayerService)
frameworks\av\media\libmediaplayerservice\MediaPlayerService.h
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\mediaserver\Main_mediaserver.cpp (server, addService)
之前的代码结构是 test_server 向 service_manager 注册服务,test_client 通过 service_manager 获取服务并使用,服务的实现和数据解析都是在单一的.c文件中实现,接下来对程序框架进行改进,将服务具体函数抽离出来模块化实现,统一由头文件分别定义服务的接口: IHelloService.h 和 IGoodbyeService.h,然后cpp文件实现具体功能:server端为 BnHelloService.cpp 和 BnGoodbyeService.cpp,client端为 BpHelloService.cpp 和 BpGoodbyeService.cpp。
(1)接口定义:(I代表interface)
①IHelloService.h
/* 参考: frameworks\av\include\media\IMediaPlayerService.h */
#ifndef ANDROID_IHELLOERVICE_H #define ANDROID_IHELLOERVICE_H #include <utils/Errors.h> // for status_t #include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <binder/IInterface.h> #include <binder/Parcel.h> #define HELLO_SVR_CMD_SAYHELLO 1 #define HELLO_SVR_CMD_SAYHELLO_TO 2 #define HELLO_SVR_CMD_GET_FD 3 namespace android { class IHelloService: public IInterface { public: DECLARE_META_INTERFACE(HelloService); //宏自动声明必须的接口 virtual void sayhello(void) = 0; virtual int sayhello_to(const char *name) = 0; virtual int get_fd(void) = 0; }; class BnHelloService: public BnInterface<IHelloService> { private: int fd; public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual void sayhello(void); virtual int sayhello_to(const char *name); virtual int get_fd(void); BnHelloService(); BnHelloService(int fd); }; } #endif
②IGoodbyeService.h
/* 参考: frameworks\av\include\media\IMediaPlayerService.h */ #ifndef ANDROID_IGOODBYEERVICE_H #define ANDROID_IGOODBYEERVICE_H #include <utils/Errors.h> // for status_t #include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <binder/IInterface.h> #include <binder/Parcel.h> #define GOODBYE_SVR_CMD_SAYGOODBYE 1 #define GOODBYE_SVR_CMD_SAYGOODBYE_TO 2 namespace android { class IGoodbyeService: public IInterface { public: DECLARE_META_INTERFACE(GoodbyeService); virtual void saygoodbye(void) = 0; virtual int saygoodbye_to(const char *name) = 0; }; class BnGoodbyeService: public BnInterface<IGoodbyeService> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual void saygoodbye(void); virtual int saygoodbye_to(const char *name); }; } #endif
(2)功能实现:(B代表binder,n代表native-本地实现,p代表proxy-代理)
①BnHelloService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */ #define LOG_TAG "HelloService" #include "IHelloService.h" namespace android { BnHelloService::BnHelloService() { } BnHelloService::BnHelloService(int fd) { this->fd = fd; } status_t BnHelloService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { /* 解析数据,调用sayhello/sayhello_to */ switch (code) { case HELLO_SVR_CMD_SAYHELLO: { sayhello(); reply->writeInt32(0); /* no exception */ return NO_ERROR; } break; case HELLO_SVR_CMD_SAYHELLO_TO: { /* 从data中取出参数 */ int32_t policy = data.readInt32(); String16 name16_tmp = data.readString16(); /* IHelloService */ String16 name16 = data.readString16(); String8 name8(name16); int cnt = sayhello_to(name8.string()); /* 把返回值写入reply传回去 */ reply->writeInt32(0); /* no exception */ reply->writeInt32(cnt); return NO_ERROR; } break; case HELLO_SVR_CMD_GET_FD: { int fd = this->get_fd(); reply->writeInt32(0); /* no exception */ /* 参考: * frameworks\base\core\jni\android_view_InputChannel.cpp * android_view_InputChannel_nativeWriteToParcel */ reply->writeDupFileDescriptor(fd); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } void BnHelloService::sayhello(void) { static int cnt = 0; ALOGI("say hello : %d\n", ++cnt); } int BnHelloService::sayhello_to(const char *name) { static int cnt = 0; ALOGI("say hello to %s : %d\n", name, ++cnt); return cnt; } int BnHelloService::get_fd(void) { return fd; } }
②BnGoodbyeService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */ #define LOG_TAG "GoodbyeService" #include "IGoodbyeService.h" namespace android { status_t BnGoodbyeService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { /* 解析数据,调用saygoodbye/saygoodbye_to */ switch (code) { case GOODBYE_SVR_CMD_SAYGOODBYE: { saygoodbye(); reply->writeInt32(0); /* no exception */ return NO_ERROR; } break; case GOODBYE_SVR_CMD_SAYGOODBYE_TO: { /* 从data中取出参数 */ int32_t policy = data.readInt32(); String16 name16_tmp = data.readString16(); /* IGoodbyeService */ String16 name16 = data.readString16(); String8 name8(name16); int cnt = saygoodbye_to(name8.string()); /* 把返回值写入reply传回去 */ reply->writeInt32(0); /* no exception */ reply->writeInt32(cnt); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } void BnGoodbyeService::saygoodbye(void) { static int cnt = 0; ALOGI("say goodbye : %d\n", ++cnt); } int BnGoodbyeService::saygoodbye_to(const char *name) { static int cnt = 0; ALOGI("say goodbye to %s : %d\n", name, ++cnt); return cnt; } }
③BpHelloService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */ #include "IHelloService.h" namespace android { class BpHelloService: public BpInterface<IHelloService> { public: BpHelloService(const sp<IBinder>& impl) : BpInterface<IHelloService>(impl) { } void sayhello(void) { /* 构造/发送数据 */ Parcel data, reply; data.writeInt32(0); data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply); } int sayhello_to(const char *name) { /* 构造/发送数据 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IHelloService")); data.writeString16(String16(name)); remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply); exception = reply.readInt32(); if (exception) return -1; else return reply.readInt32(); } int get_fd(void) { /* 构造/发送数据 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_GET_FD, data, &reply); exception = reply.readInt32(); if (exception) return -1; else { /* 参考: * frameworks\base\core\jni\android_view_InputChannel.cpp * android_view_InputChannel_nativeReadFromParcel */ int rawFd = reply.readFileDescriptor(); return dup(rawFd); } } }; IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService"); }
④BpGoodbyeService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */ #include "IGoodbyeService.h" namespace android { class BpGoodbyeService: public BpInterface<IGoodbyeService> { public: BpGoodbyeService(const sp<IBinder>& impl) : BpInterface<IGoodbyeService>(impl) { } void saygoodbye(void) { /* 构造/发送数据 */ Parcel data, reply; data.writeInt32(0); data.writeString16(String16("IGoodbyeService")); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE, data, &reply); } int saygoodbye_to(const char *name) { /* 构造/发送数据 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IGoodbyeService")); data.writeString16(String16(name)); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE_TO, data, &reply); exception = reply.readInt32(); if (exception) return -1; else return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(GoodbyeService, "android.media.IGoodbyeService"); }
(3)测试代码:
①test_server.cpp
/* 参考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */ //#define LOG_NDEBUG 0 #include <fcntl.h> #include <sys/prctl.h> #include <sys/wait.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/properties.h> #include <utils/Log.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include "IHelloService.h" #include "IGoodbyeService.h" #define SOCKET_BUFFER_SIZE (32768U) using namespace android; /* 参考: * http://blog.csdn.net/linan_nwu/article/details/8222349 */ class MyThread: public Thread { private: int fd; public: MyThread() {} MyThread(int fd) { this->fd = fd; } //如果返回true,循环调用此函数,返回false下一次不会再调用此函数 bool threadLoop() { char buf[500]; int len; int cnt = 0; while(1) { /* 读数据: test_client发出的数据 */ len = read(fd, buf, 500); buf[len] = '\0'; ALOGI("%s\n", buf); /* 向 test_client 发出: Hello, test_client */ len = sprintf(buf, "Hello, test_client, cnt = %d", cnt++); write(fd, buf, len); } return true; } }; /* usage : test_server */ int main(void) { int sockets[2]; socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets); int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); /* 创建一个线程, 用于跟test_client使用socketpiar通信 */ sp<MyThread> th = new MyThread(sockets[0]); th->run(); /* addService */ /* while(1){ read data, 解析数据, 调用服务函数 } */ /* 打开驱动, mmap */ sp<ProcessState> proc(ProcessState::self()); /* 获得BpServiceManager */ sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("hello"), new BnHelloService(sockets[1])); sm->addService(String16("goodbye"), new BnGoodbyeService()); /* 循环体 */ ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; }
②test_client.cpp
//#define LOG_NDEBUG 0 #include <fcntl.h> #include <sys/prctl.h> #include <sys/wait.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/properties.h> #include <utils/Log.h> #include <unistd.h> #include "IHelloService.h" #include "IGoodbyeService.h" using namespace android; /* ./test_client <hello|goodbye> * ./test_client <readfile> * ./test_client <hello|goodbye> <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()); /* 获得BpServiceManager */ sp<IServiceManager> sm = defaultServiceManager(); if (strcmp(argv[1], "hello") == 0) { sp<IBinder> binder = sm->getService(String16("hello")); if (binder == 0) { ALOGI("can't get hello service\n"); return -1; } /* service肯定是BpHelloServie指针 */ sp<IHelloService> service = interface_cast<IHelloService>(binder); /* 调用Service的函数 */ if (argc < 3) { service->sayhello(); 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) { sp<IBinder> binder = sm->getService(String16("hello")); if (binder == 0) { ALOGI("can't get hello service\n"); return -1; } /* service肯定是BpHelloServie指针 */ sp<IHelloService> service = interface_cast<IHelloService>(binder); /* 调用Service的函数 */ int fd = service->get_fd(); ALOGI("client call get_fd = %d", fd); char buf[500]; int len; int cnt = 0; while (1) { /* 向 test_server 进程发出: Hello, test_server */ len = sprintf(buf, "Hello, test_server, cnt = %d", cnt++); write(fd, buf, len); /* 读取数据(test_server进程发回的数据) */ len = read(fd, buf, 500); buf[len] = '\0'; ALOGI("%s\n", buf); sleep(5); } } else { sp<IBinder> binder = sm->getService(String16("goodbye")); if (binder == 0) { ALOGI("can't get goodbye service\n"); return -1; } /* service肯定是BpGoodbyeServie指针 */ sp<IGoodbyeService> service = interface_cast<IGoodbyeService>(binder); /* 调用Service的函数 */ if (argc < 3) { service->saygoodbye(); ALOGI("client call saygoodbye"); } else { cnt = service->saygoodbye_to(argv[2]); ALOGI("client call saygoodbye_to, cnt = %d", cnt); } } return 0; }
(4)Android.mk:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BnHelloService.cpp \ BpHelloService.cpp \ BnGoodbyeService.cpp \ BpGoodbyeService.cpp \ test_server.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ liblog \ libbinder LOCAL_MODULE:= test_server LOCAL_32_BIT_ONLY := true include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BpHelloService.cpp \ BpGoodbyeService.cpp \ test_client.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ liblog \ libbinder LOCAL_MODULE:= test_client LOCAL_32_BIT_ONLY := true include $(BUILD_EXECUTABLE)
二、内部机制
1.回顾binder框架关键点
test_server向service_manager添加服务,test_client通过service_manager获取服务,具体流程如下:
①add_service:
a.test_server为每个服务构造 struct flat_binder_object 结构体,其中void *binder 或 void* cookie 对应不同服务;
b.调用ioctl发送数据:
b1. 数据:flat_binder_object + 服务名称;
b2.数据中含有"目的地":handle=0,则代表 service_manager;
c.驱动程序对每一个flat_binder_object构造一个binder_node结构体,其中 void __user *ptr 和 void __user *cookie即来自flat_binder_object;
d.驱动程序根据handle=0找到service_manager,把数据发送给service_manager并且创建一个 struct binder_ref结构体到链表,其中node指针指向binder_node结构体;
e.service_manager中记录服务名(“hello”、“goodbye”)称和desc值(binder_ref结构体中的desc值);
②get_service:
a.test_client构造数据:名称 + "目的"(handle=0);
b.调ioctl发送数据;
c.驱动程序根据handle=0找到service_manager把数据给service_manager;
d.service_manager从service list中找到对应项,比如根据服务名"hello"找到第一项,handle=1;
e.service_manager调用ioctl返回数据(flat_binder_object);
f.驱动发现数据中含有flat_binder_object,且type为引用,从service_manager的binder_ref表中找到对应项(传入的handle=binder_ref.desc)再找到binder_node,最后为test_client建立binder_ref,即对应service_manager里构造的binder_ref链表;
③test_client使用服务: hello->sayhello(code=1), hello->sayhello_to(code=2)
a.构造数据,code定义要执行的函数、参数、目的(handle=1);
b.使用ioctl发送数据;
c.驱动从数据中取出handle=1,根据handle找到binder_ref,根据binder_ref找到binder_node,再根据binder_node找到目的进程(.proc->test_server),最后把数据传给test_server,并且在数据中设置.ptr/.cookie 等于binder_node的.ptr/.cookie;
d.test_server根据.ptr/.cookie获知test_client想调用的服务,再根据code等参数调用具体的函数操作;
小结:
server注册服务时, 对每个服务都提供不同的ptr/cookie,在驱动程序里对每个服务都构造一个binder_node, 它也含有ptr/cookie,client使用服务前要先getService,在驱动程序里对该服务构造一个binder_ref,binder_ref含有desc, node成员, desc是整数, node指向对应服务的binder_node,使用服务时, client调用ioctl发送构造数据,数据里含有handle,驱动程序根据handle找到binder_ref(desc==handle), 再通过binder_ref找到binder_node, 再根据binder_node找到对应server,最后从binder_node取出ptr/cookie连同那些数据发给server,server根据数据中的ptr/cookie信息调用对应服务,再根据code调用对应函数。
Binder系统最核心的函数: ioclt;
client最核心的数据:handle;
server最核心的数据:.ptr/.cookie
2.代理类BpXXX分析
test_server向service_manager添加服务时,首先获得BpServiceManager(handle=0)成为一个client与之通信,test_client同样获得BpServiceManager和service_manager通信,然后test_client再获得BpHelloService(handle=BpServiceManager->getService("Hello")==1)和test_server通信。
UML展示BpServiceManager的继承关系:
(1)
(2)
(3)
2.1 获得BpServiceManager对象的过程:
defaultServiceManager构造了一个BpServiceManager对象(派生自BpRefBase,含有IBinder *mRemote, mRemote指向BpBinder对象,它含有mHandle),
其中它的mRemote = new BpBinder(0); // mRemote->mHandle=0
defaultServiceManager // IServiceManager.cpp
// 把BpBinder(mHandle=0)对象转换为IServiceManager接口(BpServiceManager)
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
分析:
ProcessState::self()->getContextObject(NULL)
getStrongProxyForHandle(0);
b = new BpBinder(handle); // mHandle=handle=0
interface_cast<IServiceManager>(new BpBinder(0)) // IInterface.h
IServiceManager::asInterface(obj);
return new BpServiceManager(obj); // mRemote=obj=new BpBinder(0);
2.2 获得BpHelloService对象的过程:
调用BpServiceManager的getService函数获得一个flat_binder_object,
从中取出handle, 创建一个BpBinder(handle),
然后使用interface_cast使用这个BpBinder创建一个BpHelloService对象
// binder是BpBinder对象, 里面含有HelloService的handle
sp<IBinder> binder =
sm->getService(String16("hello")); // IServiceManager.cpp
// 构造数据: 数据中肯定含有"hello"
// 发送数据: 给handle 0, 即 service_manager进程
// 从收到的回复中取出HelloService的handle
return reply.readStrongBinder();
unflatten_binder(ProcessState::self(), *this, &val);
*out = proc->getStrongProxyForHandle(flat->handle);
new BpBinder(handle); //handle来自service_manager进程的回复
// 把binder转换为IHelloService接口(BpHelloService对象)
// binder是BpBinder对象, 里面含有HelloService的handle
sp<IHelloService> service = interface_cast<IHelloService>(binder);
2.3 代理类如何发送数据: ioctl, 数据里含有handle, 含有其他构造的参数
构造好数据之后,调用:
remote()->transact(...) //addService、checkService、getService 以及sayhello/sayhello_to等函数最终都会调用这里,remote()返回一个BpBinder对象,其中实现了transact;
IPCThreadState::self()->transact(mHandle, code, data, reply, flags); //该线程中实现了waitForResponse()、talkWithDriver(其中通过mDriverFD句柄进行ioctl操作) 等函数。
3.数据传输:ProcessState 和 IPCThreadState 类 (单例模式)
ProcessState::self()->startThreadPool(); //创建子线程,最终执行:IPCThreadState ::self()->joinThreadPool();
IPCThreadState ::self()->joinThreadPool(); //循环,读取数据、解析、处理、回复。
3.1 addService
前面介绍过,对于不同服务构造的flat_binder_object结构体,里面的.binder/.cookie对于不同的服务它的值不一样
sm->addService(String16("hello"), new BnHelloService());
data.writeStrongBinder(service); // service = new BnHelloService();
flatten_binder(ProcessState::self(), val, this); // val = service = new BnHelloService();
flat_binder_object obj; // 参数 binder = val = service = new BnHelloService();
IBinder *local = binder->localBinder(); // =this = new BnHelloService();
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local); // new BnHelloService();
3.2 server如何分辨client想使用哪一个服务?
server收到数据里含有flat_binder_object结构体,
它可以根据.binder/.cookie分析client想使用哪一个服务
把.cookie转换为BnXXXX对象,然后调用它的函数:
// 根据cookie构造了一个BBinder指针, 实际上是指向某个BnXXX对象
sp<BBinder> b((BBinder*)tr.cookie);
// 然后调用它的transact函数
error = b->transact(tr.code, buffer, &reply, tr.flags);
err = onTransact(code, data, reply, flags); // 就会调用到BnXXX里实现的onTransact
// 它就会根据code值来调用不同的函数
-end-
posted on 2019-03-09 16:55 sheldon_blogs 阅读(2382) 评论(0) 编辑 收藏 举报