步骤1 创建一个继承于 IInterface的基类
参考代码如下
在头文件中:
class IMyTestBase: public IInterface
{
public:
DECLARE_META_INTERFACE(MyTestBase);
virtual int Test( unsigned int input,unsigned int * output ) = 0;
};
说明:
DECLARE_META_INTERFACE 定义在frameworks\native\include\binder\IInterface.h中,
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE();
这个宏实际上就是定义了这个类的构造函数和析构函数。定义了一个descriptor的字符串和getInterfaceDescriptor和asInterface的方法,descriptor是service的标示,用于BP和BN通讯的唯一标识。
DECLARE_META_INTERFACE的参数一定要和类名I后面的名称是对应的。
IMyTestBase类中的Test就是我们要提供的接口,也就是在其他的应用中通过Remote端要调用的接口。
在C文件中:
IMPLEMENT_META_INTERFACE(MyTestBase, "MyTestBase.name");
说明:
IMPLEMENT_META_INTERFACE也是定义在frameworks\native\include\binder\IInterface.h中
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { }
通过上面的定义可以看出,这个宏实际上就是实现了IMyTestBase类。
步骤2 定义一个本地的服务BnXXX,继承于BnInterface<IXXXService>,并实现OnTransact()函数。然后实现一个service,继承于BnXXX,在该类实现本服务要提供的接口。另外实现一个静态函数static int instantiate()在这个函数里调用addService添加本服务。
下面是示例代码:
1 实现BnMyTestBase
在头文件中定义一个BnMyTestBase
class BnMyTestBase: public BnInterface<IMyTestBase>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
在C文件中实现该类
status_t BnMyTestBase::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case TEST_CODE:
{
CHECK_INTERFACE(IMyTestBase, data, reply);
unsigned int input = (unsigned int )data.readInt32();
unsigned int output ;
int ret = Test(input, &output );
reply->writeInt32(output);
reply->writeInt32(ret);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
2 实现 MyTestService
在头文件中:
class MyTestService: public BnMyTestBase
{
public:
static int instantiate();
virtual int Test( unsigned int input,unsigned int * output );
MyTestService( void );
~MyTestService( void );
};
在C文件中
int MyTestService::instantiate()
{
status_t ret = defaultServiceManager()->addService( String16("MYTEST"), new MyTestService());
if(ret == NO_ERROR)
{
ALOGD("addService MyTestService sucess" );
return 0;
}
else
{
ALOGD("addService MyTestService failed ret=0x%x" ,ret );
return -1;
}
}
MyTestService::MyTestService( )
{
ALOGD("MyTestService init" );
}
int MyTestService::Test( unsigned int input,unsigned int * output )
{
ALOGD("test input=%d" ,input);
*output=0xaa;
return 0;
}
MyTestService::~MyTestService( void )
{
ALOGD("MyTestService deinit" );
}
步骤3 定义一个remote sevice BpXXX,继承BpInterface<IXXXService>
示例代码如下:
在头文件中
class BpMyTestBase: public BpInterface<IMyTestBase>
{
public:
BpMyTestBase(const sp<IBinder>& impl)
: BpInterface<IMyTestBase>(impl)
{
}
virtual int Test( unsigned int input,unsigned int * output )
{
Parcel data, reply;
data.writeInterfaceToken(IMyTestBase::getInterfaceDescriptor());
data.writeInt32(input);
remote()->transact(TEST_CODE, data, &reply);
*output = reply.readInt32();
return (reply.readInt32());
}
};
完成这3步,我们的服务就定义好了。
说明:
1 我们定义的服务一定要用namespace android 括起来,否则编译时会报错。
2 在BN和BP之间通过Parcel 传递参数的时候,write和read的顺序是一样的。这里不是堆栈,不存在后进先出。
3 在MyTestService::instantiate函数中addService的第一个参数是添加的服务的名字,这个名字是唯一的,我们在应用中要使用这个服务,就是通过这个名字来寻找的。
步骤4 :启动这个服务
我们定义一个可执行程序,来调用instantiate,添加服务。然后再Init.rc文件中启动这个可执行程序。
参考代码如下:
using namespace android;
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
if(MyTestService::instantiate()<0)
{
exit(0);
}
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
编译下载好后重新启动机器,在adb shell界面中输入service list命令,就可以看到我们定义的服务了。
如果服务没有启动,可能是权限问题,可以参考《android init.rc文件语法详解》添加selinux的权限。
步骤5:在应用中调用这个服务
参考代码如下
sp<IMyTestBase> sService ;
const sp<IMyTestBase>& getService( )
{
int icount =0;
if (sService.get() == 0)
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
binder = sm->getService(String16("MYTEST"));
if (binder != 0)
{
sService = interface_cast<IMyTestBase>(binder);
}
}
return sService;
}
调用服务的接口
const sp<IMyTestBase>& service(getService());
unsigned int input=0,output;
service->Test(input,&output);
OK !大功告成!
不过如果在android5.0之后,可能调用会失败,因为我们还没有定义selinux的权限。
下面介绍下如何添加权限。
假设我们启动这个服务的应用是/system/bin/Start__server这个程序。
首先我们要在创建一个Start__server.te。在里面定义
type Start__server, domain;
type Start__server_exec, exec_type, file_type;
init_daemon_domain(Start__server)
在file_contexts文件里面添加
/system/bin/Start__server u:object_r:Start__server_exec:s0
在service_contexts文件中添加
MYTEST u:object_r:system_server_service:s0
注意这里的MYTEST就是我们调用addService的第一个参数,这里要完全对应。
然后重新编译运行,我们会看到logcat的调试信息由很多下面的错误
avc: denied { add } for service=MYTEST scontext=u:r:Start__server:s0 tcontext=u:object_r:system_server_service:s0 tclass=service_manager
avc: denied { call } for scontext=u:r:untrusted_app:s0 tcontext=u:r:Start__server:s0 tclass=binder permissive=0avc: denied { search } for name="150" dev="proc" ino=4877 scontext=u:r:servicemanager:s0 tcontext=u:r:Start__server:s0 tclass=dir permissive=0
等等很多错误信息。
我们可以参考《android init.rc文件语法详解》介绍的方法在Start__server.te中一条条添加相应的权限。
另外还有更简洁的办法,google已经定义好了宏,我们直接拿来用就好了。
我们只要简单的在Start__server.te添加下面的语句
allow Start__server system_server_service:service_manager add;
binder_use(Start__server)
binder_call(appdomain,Start__server)
说明binder_call第一个参数是允许使用这个服务的应用的类型。
appdomain则说明说有的应用都可以使用。
我们可以根据需要制定其他的类型例如platform_app、untrusted_app
也可以指定某一个应用程序例如shell、adbd、mediaserver等等。
参考代码如下
在头文件中:
class IMyTestBase: public IInterface
{
public:
DECLARE_META_INTERFACE(MyTestBase);
virtual int Test( unsigned int input,unsigned int * output ) = 0;
};
说明:
DECLARE_META_INTERFACE 定义在frameworks\native\include\binder\IInterface.h中,
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE();
这个宏实际上就是定义了这个类的构造函数和析构函数。定义了一个descriptor的字符串和getInterfaceDescriptor和asInterface的方法,descriptor是service的标示,用于BP和BN通讯的唯一标识。
DECLARE_META_INTERFACE的参数一定要和类名I后面的名称是对应的。
IMyTestBase类中的Test就是我们要提供的接口,也就是在其他的应用中通过Remote端要调用的接口。
在C文件中:
IMPLEMENT_META_INTERFACE(MyTestBase, "MyTestBase.name");
说明:
IMPLEMENT_META_INTERFACE也是定义在frameworks\native\include\binder\IInterface.h中
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { }
通过上面的定义可以看出,这个宏实际上就是实现了IMyTestBase类。
步骤2 定义一个本地的服务BnXXX,继承于BnInterface<IXXXService>,并实现OnTransact()函数。然后实现一个service,继承于BnXXX,在该类实现本服务要提供的接口。另外实现一个静态函数static int instantiate()在这个函数里调用addService添加本服务。
下面是示例代码:
1 实现BnMyTestBase
在头文件中定义一个BnMyTestBase
class BnMyTestBase: public BnInterface<IMyTestBase>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
在C文件中实现该类
status_t BnMyTestBase::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case TEST_CODE:
{
CHECK_INTERFACE(IMyTestBase, data, reply);
unsigned int input = (unsigned int )data.readInt32();
unsigned int output ;
int ret = Test(input, &output );
reply->writeInt32(output);
reply->writeInt32(ret);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
2 实现 MyTestService
在头文件中:
class MyTestService: public BnMyTestBase
{
public:
static int instantiate();
virtual int Test( unsigned int input,unsigned int * output );
MyTestService( void );
~MyTestService( void );
};
在C文件中
int MyTestService::instantiate()
{
status_t ret = defaultServiceManager()->addService( String16("MYTEST"), new MyTestService());
if(ret == NO_ERROR)
{
ALOGD("addService MyTestService sucess" );
return 0;
}
else
{
ALOGD("addService MyTestService failed ret=0x%x" ,ret );
return -1;
}
}
MyTestService::MyTestService( )
{
ALOGD("MyTestService init" );
}
int MyTestService::Test( unsigned int input,unsigned int * output )
{
ALOGD("test input=%d" ,input);
*output=0xaa;
return 0;
}
MyTestService::~MyTestService( void )
{
ALOGD("MyTestService deinit" );
}
步骤3 定义一个remote sevice BpXXX,继承BpInterface<IXXXService>
示例代码如下:
在头文件中
class BpMyTestBase: public BpInterface<IMyTestBase>
{
public:
BpMyTestBase(const sp<IBinder>& impl)
: BpInterface<IMyTestBase>(impl)
{
}
virtual int Test( unsigned int input,unsigned int * output )
{
Parcel data, reply;
data.writeInterfaceToken(IMyTestBase::getInterfaceDescriptor());
data.writeInt32(input);
remote()->transact(TEST_CODE, data, &reply);
*output = reply.readInt32();
return (reply.readInt32());
}
};
完成这3步,我们的服务就定义好了。
说明:
1 我们定义的服务一定要用namespace android 括起来,否则编译时会报错。
2 在BN和BP之间通过Parcel 传递参数的时候,write和read的顺序是一样的。这里不是堆栈,不存在后进先出。
3 在MyTestService::instantiate函数中addService的第一个参数是添加的服务的名字,这个名字是唯一的,我们在应用中要使用这个服务,就是通过这个名字来寻找的。
步骤4 :启动这个服务
我们定义一个可执行程序,来调用instantiate,添加服务。然后再Init.rc文件中启动这个可执行程序。
参考代码如下:
using namespace android;
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
if(MyTestService::instantiate()<0)
{
exit(0);
}
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
编译下载好后重新启动机器,在adb shell界面中输入service list命令,就可以看到我们定义的服务了。
如果服务没有启动,可能是权限问题,可以参考《android init.rc文件语法详解》添加selinux的权限。
步骤5:在应用中调用这个服务
参考代码如下
sp<IMyTestBase> sService ;
const sp<IMyTestBase>& getService( )
{
int icount =0;
if (sService.get() == 0)
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
binder = sm->getService(String16("MYTEST"));
if (binder != 0)
{
sService = interface_cast<IMyTestBase>(binder);
}
}
return sService;
}
调用服务的接口
const sp<IMyTestBase>& service(getService());
unsigned int input=0,output;
service->Test(input,&output);
OK !大功告成!
不过如果在android5.0之后,可能调用会失败,因为我们还没有定义selinux的权限。
下面介绍下如何添加权限。
假设我们启动这个服务的应用是/system/bin/Start__server这个程序。
首先我们要在创建一个Start__server.te。在里面定义
type Start__server, domain;
type Start__server_exec, exec_type, file_type;
init_daemon_domain(Start__server)
在file_contexts文件里面添加
/system/bin/Start__server u:object_r:Start__server_exec:s0
在service_contexts文件中添加
MYTEST u:object_r:system_server_service:s0
注意这里的MYTEST就是我们调用addService的第一个参数,这里要完全对应。
然后重新编译运行,我们会看到logcat的调试信息由很多下面的错误
avc: denied { add } for service=MYTEST scontext=u:r:Start__server:s0 tcontext=u:object_r:system_server_service:s0 tclass=service_manager
avc: denied { call } for scontext=u:r:untrusted_app:s0 tcontext=u:r:Start__server:s0 tclass=binder permissive=0avc: denied { search } for name="150" dev="proc" ino=4877 scontext=u:r:servicemanager:s0 tcontext=u:r:Start__server:s0 tclass=dir permissive=0
等等很多错误信息。
我们可以参考《android init.rc文件语法详解》介绍的方法在Start__server.te中一条条添加相应的权限。
另外还有更简洁的办法,google已经定义好了宏,我们直接拿来用就好了。
我们只要简单的在Start__server.te添加下面的语句
allow Start__server system_server_service:service_manager add;
binder_use(Start__server)
binder_call(appdomain,Start__server)
说明binder_call第一个参数是允许使用这个服务的应用的类型。
appdomain则说明说有的应用都可以使用。
我们可以根据需要制定其他的类型例如platform_app、untrusted_app
也可以指定某一个应用程序例如shell、adbd、mediaserver等等。