Native Service的实现

步骤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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值