1.定义一个接口类IHelloService.h
功能:定义业务接口sayhello和sayhello_to
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 0
#define HELLO_SVR_CMD_SAYHELLO_TO 1
namespace android {
class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService);
virtual void sayhello(void) = 0;
virtual int sayhello_to(const char *name) = 0;
};
class BnHelloService: public BnInterface<IHelloService>
{
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);
};
}
#endif
BnHelloService是继承public BnInterface,其中BnInterface是一个模板类,
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};
所以BnHelloService是继承IHelloService和BBinder两个基类。
2.binder的native服务实现: BnHelloService.cpp
功能:实现业务接口sayhello和sayhello_to两个方法,以及onTransact方法。
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */
#define LOG_TAG "HelloService"
#include "IHelloService.h"
namespace android {
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();
return NO_ERROR;
} break;
case HELLO_SVR_CMD_SAYHELLO_TO: {
/* 从data中取出参数 */
int32_t policy = data.readInt32();
String16 name16 = data.readString16();
String8 name8(name16);
int cnt = sayhello_to(name8.string());
/* 把返回值写入reply传回去 */
reply->writeInt32(cnt);
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;
}
}
3.binder的proxy实现:BpHelloService.cpp
功能:调用sayhello和sayhello_to两个方法
/* 参考: 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);
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
int sayhello_to(const char *name)
{
/* 构造/发送数据 */
Parcel data, reply;
data.writeInt32(0);
data.writeString16(String16(name));
remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
}
BpHelloService:继承自public BpInterface,BpInterface的模板类如下:
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder* onAsBinder();
};
所以BpHelloService是继承IHelloService和BpRefBase两个基类。
test_server.cpp
/* 参考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */
#define LOG_TAG "HelloService"
//#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 "IHelloService.h"
using namespace android;
int main(void)
{
/* addService */
/* while(1){ read data, 解析数据, 调用服务函数 } */
/* 打开驱动, mmap */
sp<ProcessState> proc(ProcessState::self());
/* 获得BpServiceManager */
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16("hello"), new BnHelloService());
/* 循环体 */
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
test_client.cpp
#define LOG_TAG "HelloService"
//#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 "IHelloService.h"
using namespace android;
/* ./test_client hello
* ./test_client hello <name>
*/
int main(int argc, char **argv)
{
int cnt;
if (argc < 2){
ALOGI("Usage:\n");
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();
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);
}
return 0;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
BnHelloService.cpp \
BpHelloService.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 \
test_client.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libbinder
LOCAL_MODULE:= test_client
LOCAL_32_BIT_ONLY := true
include $(BUILD_EXECUTABLE)
总结
服务端:
让我们用图梳理一下 (箭头代表继承关系)
归纳一下,
- BBinder 实现了大部分的IBinder 接口,除了onTransact() 和 queryLocalInterface(), getInterfaceDescriptor();
- BnInterface 实现了IBinder的queryLocalInterface()和getInterfaceDescriptor(), 但是其必须借助实际的接口类。
- BnMediaPlayer只是定义并实现了onTransact()。
客户端:
BpRefBase 里有IBinder 成员变量,看来在客户端,没有一个类同时继承IBinder 和 IInterface, 但是有一个类继承了其一,但包含了另外一个,这种在设计模式里成为组合(Composition).
客户端中的BpRefBase类中包含IBinder类:
可以通过interface_cast 直接把IBinder 转换成了 IMediaPlayer
总结:
flat_binder_object结构体如下:
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void *cookie;
};
addService时,
- 1.会为每个服务构造一个flat_binder_object 结构体,每个服务的flat_binder_object 中的binder(binder = reinterpret_cast<uintptr_t>(local->getWeakRefs()))和cookie都不同。
- 2.调用ioctl发送数据,数据中包含flat_binder_object 结构体,服务的名字(即media.player),发送的目的地(handle = 0,即servicemanager)。
- 3.驱动程序对每一个flat_binder_object构造一个binder_node节点。
- 4.驱动程序根据handle=0找到sm,把这些数据发送给sm驱动层,并且创建binder_ref结构体,其中的binder_node元素指向上述的binder_node节点。
- 5.sm的进程还会创建一个svlist的链表,里面挂载svcinfo结构体,含有name和handle值,handle即为驱动程序中binder_ref的desc值。
struct svcinfo
{
struct svcinfo *next;
uint32_t handle;
…
uint16_t name[0];
};
struct binder_node {
...
struct binder_work work;
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};
struct binder_proc *proc;
struct hlist_head refs;
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
binder_uintptr_t ptr;//来自flat_binder_object中的binder
binder_uintptr_t cookie;//来自flat_binder_object中的cookie
...
};
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
int debug_id;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;
struct binder_proc *proc;
struct binder_node *node;
uint32_t desc;
int strong;
int weak;
struct binder_ref_death *death;
};
getService时
- 1.Client想去获得服务,并且传输数据,数据=名称+“目的(handle = 0)”.
- 2.调用ioctl发送数据.
- 3.驱动程序根据handle=0找到sm,把数据给sm.
- 4.sm从svlist找到对应项,比如根据名称(media.player)找到handle=1。
- 5.sm通过ioctl返回数据,数据也是flat_binder_object,其中的handle=1
- 6.通过5,驱动发现数据中有flat_binder_object结构体,且type为引用,binder_ref里面找到对应项(传入的handle值等于binder_ref的desc),再找到binder_node,最后为client的内核空间也建立binder_ref链表。
client怎么使用服务
- 1.构造数据,里面含有code(通过code值决定调用哪个函数)、参数、目的(handle=1)
- 2.使用ioctl发数据。
- 3.驱动根据handle=1,找到binder_ref,根据binder_ref找到binder_node,根据binder_node中的binder_proc找到server进程。最后把数据传给server,并且在数据中设置ptr和cookie等于binder_node的ptr和cookie。server根据ptr和cookie确定找到哪个服务,根据code调用相应的函数。
综上:client中最核心的数据是handle,server最核心的数据是ptr/cookie。