Native Service的实现

来源:互联网 发布:java工程师工作内容 编辑:程序博客网 时间:2024/06/05 20:44
步骤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等等。

0 0
原创粉丝点击