从零开始怎么写android native service?

本文详细介绍如何从零开始创建 Android Native Service,包括定义服务接口、实现服务代理和 stub,以及编写服务实体等关键步骤,并提供测试和服务调用的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.2cto.com/kf/201602/490149.html


Android service对于从事android开发的人都不是一个陌生的东西,很多人可能会觉得服务很简单。服务是简单,因为复杂的别人做了,所以才会觉得简单。我们先梳理一下服务的分类,首先有本地服务跟系统服务的区分,而在APP里写的服务大多就成为Java服务或者应用服务。

做APP的人写个应用服务相对来说是最简单的,因为extends了一个service后几个简单的接口就可以跑起来了,写完这种服务可能也只是对服务一知半解,因为值钱的service类Google的人已经帮你写好了,这是你的福气为你带来了便利,当然也可能会麻痹你:),但是做APP的人会有能解决问题是首要任务了,有时间还是对它了解更清楚点比较好,在此不再讨论这个。

做设备做系统的人,经常可能会去写系统服务,也就是framework下面的服务,systemserver里面注册的服务,写这种服务一般来说比较少,只有做设备系统的才会这样干,才有机会有完成的系统代码,可以在里面自由遨游,笔者三年前写过一个,可以看看【自己动手从零开始写一个完整的android Service

那剩下的一个是本地服务,也就是native service,这种服务我们了解的系统里面多媒体、audio system都是写成了本地服务,这样写的好处就是运行的效率更高一点,因为C/C++先天性就比JAVA的运行效率要高一点。笔者就是由于长期主要从事的都是底层开发的,我们有时有这么一种需求,又要运行效率高,又要好移植,主要是考虑推广写东西给广大客户,那么我就写一个本地服务,这样是最独立的了,效率也最高了,那一个本地服务到底怎么写呢?大多数的人写过的服务以java服务居多,真正写本地服务的不多,本地服务相对来说又是更复杂一点的。因此决定从零开始自己动手写一个本地service,下面就大概描述一下过程。

本地服务有四大块,服务接口(IService),服务代理(也就是BpService),服务stub(也就是BnService),服务实体(Service);下面笔者的实例就以demoNativeService来开启,力求简单,里面就写了两个接口;

首先定义好服务接口IdemoNativeService,IdemoNativeService服务接口的父类是IInterface,在里面主要是要声明一下接口,在DECLARE_META_INTERFACE(demoNativeService),代码如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class IdemoNativeService : public IInterface
{
public :
     enum {
         CONNECT = IBinder::FIRST_CALL_TRANSACTION,
         PRINTSTRING_CMD,
     };
 
public :
     DECLARE_META_INTERFACE(demoNativeService);
     virtual status_t connect( int pid, int previewhw, int intf, int fmt, int chan) = 0 ;
   virtual  status_t  printString( const char *str) = 0 ;
 
};

 

当然定义好了IdemoNativeService的头文件,就需要去实操了,先来搞定BpdemoNativeService,它的父类是BpInterface,这里面主要是涉及数据的跨进程用到的parcel,读啊,写啊,按套路来,也不难,也有AIDL工具可以使用,帮你转出来,再稍微修改一下就可以了,里面有一个很重要的remote,这个和remote就是幕后功臣啊,它保存了服务实例的对象啊,它是来之BpRefBase的一个成员,生成服务的时候,会得到赋值,定义完了以后,很重要的一个程序就是要IMPLEMENT_META_INTERFACE(demoNativeService,"android.hardware.IdemoNativeService");这个宏是非常重要的,跟前面那个DECLARE是对应的,前面声明,后面实现,当然我们带的参数跟的名字是必须一致的,这样才能正常沟通嘛!

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class BpdemoNativeService: public BpInterface<idemonativeservice>
{
public :
     BpdemoNativeService( const sp<ibinder>& impl)
     : BpInterface<idemonativeservice>(impl)
     {
     }
 
     virtual status_t connect( int pid, int previewhw, int intf, int fmt, int chan)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IdemoNativeService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt32(previewhw);
         data.writeInt32(intf);
         data.writeInt32(fmt);
         data.writeInt32(chan);
         remote()->transact(IdemoNativeService::CONNECT, data, &reply);
         return reply.readInt32();
     }
 
   virtual  status_t  printString( const char *str)
   {
     Parcel data, reply;
     data.writeInterfaceToken(IdemoNativeService::getInterfaceDescriptor());
     data.writeCString(str);
     remote()->transact(IdemoNativeService::PRINTSTRING_CMD, data, &reply);
         return reply.readInt32();
   }
};
 
IMPLEMENT_META_INTERFACE(demoNativeService, "android.hardware.IdemoNativeService" ); //android.hardware.IdemoNativeService ds.demonativeservice</idemonativeservice></ibinder></idemonativeservice>

 

接着需要写服务stub了,BndemoNativeService的父类是BnInterface,有没有发现BndemoNativeService跟BpdemoNativeService,都会基于接口类IdemoNativeService,这样沟通起来的接口就唯一了,就具备了对话的可能;

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class BndemoNativeService: public BnInterface<idemonativeservice>
{
public :
     virtual status_t onTransact( uint32_t code, const Parcel& data,Parcel* reply,uint32_t flags = 0 );
};
status_t BndemoNativeService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
     switch (code)
     {
         /*case CONNECT: {
             CHECK_INTERFACE(IdemoNativeService, data, reply);
             int pid         = data.readInt32();
             int previewhw   = data.readInt32();
             int intf        = data.readInt32();
             int fmt         = data.readInt32();
             int chan        = data.readInt32();
             reply->writeInt32(connect(pid,previewhw,intf,fmt,chan));
             return NO_ERROR;
             }break;
         case PRINTSTRING_CMD: {
             CHECK_INTERFACE(IdemoNativeService, data, reply);
             const char *str;
       str = data.readCString();
             reply->writeInt32(printString(str));
             return NO_ERROR;
             }break;*/
 
         default :
             return BBinder::onTransact(code, data, reply, flags);
     }
}</idemonativeservice>

 

到这就轮到了大块头service实体demoNativeService了,demoNativeService是基于BndemoNativeService,在demoNativeService里面定义了一个instantiate()接口用于添加service到servicemanager里面去,注意demoNativeService()跟析构函数~demoNativeService()需要写成private的,免得别人可以new出对象来。在里面重写了onTransact,一旦BpdemoNativeService有风吹草动,就会联动到BndemoNativeService,因为服务实体重写了onTransact,所以实际就会先执行到demoNativeService::onTransact这里来,在这里面处理不了,可以再转给BpdemoNativeService的onTransact或者直接到BBinder的onTransact;

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
void demoNativeService::instantiate() {
     android::defaultServiceManager()->addService(
                 IdemoNativeService::descriptor, new demoNativeService());
}
 
demoNativeService::demoNativeService()
{
     ALOGE( "demoNativeService created" );
     mOpened = 1 ;
}
 
demoNativeService::~demoNativeService()
{
     ALOGE( "demoNativeService destroyed" );
}
 
  status_t  demoNativeService::connect( int pid, int previewhw, int intf, int fmt, int chan){
     
     ALOGD( "demoNativeService connect:%d, %d, %d, %d, %d" , pid, previewhw, intf, fmt, chan);
     return 88 ;
     
}
 
  status_t  demoNativeService::printString( const char *str){
       ALOGD( "demoNativeService printString:%s" , str);
     return 66 ;
}
      
# if 1      
  status_t demoNativeService::onTransact(uint32_t code,
                                                 const android::Parcel &data,
                                                 android::Parcel *reply,
                                                 uint32_t flags)
{
         ALOGD( "OnTransact(%u,%u)" , code, flags);
         
         switch (code) {
         case CONNECT: {
             CHECK_INTERFACE(IdemoNativeService, data, reply);
             int pid         = data.readInt32();
             int previewhw   = data.readInt32();
             int intf        = data.readInt32();
             int fmt         = data.readInt32();
             int chan        = data.readInt32();
             
       ALOGD( "CONNECT: %d, %d, %d, %d, %d\n" , pid,previewhw,intf,fmt,chan);
             reply->writeInt32(connect(pid,previewhw,intf,fmt,chan));
             return NO_ERROR;
             } break ;
                                 
         case PRINTSTRING_CMD: {
                 CHECK_INTERFACE(IdemoNativeService, data, reply);
                 const char *str;
                 str = data.readCString();
                 ALOGD( "PrintString: %s\n" , str);
                 ALOGD( "printString: %s\n" , str);
                                 reply->writeInt32(printString(str));
                 return NO_ERROR;
         } break ;
         default :
                 return BndemoNativeService::onTransact(code, data, reply, flags);
         }
 
         return NO_ERROR;
}
#endif

 

写完了服务,那我们就再写一个可执行文件来生成一下,里面startThreadPool生成线程池,然后再调用joinThreadPool来监听变化;

 

?
1
2
3
4
5
6
     sp<processstate> proc(ProcessState::self());
     sp<iservicemanager> sm = defaultServiceManager();
//    ALOGI("ServiceManager: %p", sm.get());
     demoNativeService::instantiate();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();</iservicemanager></processstate>

 

写到这,可以说服务已经可以跑起来了,那我们怎么验证呢,最快的办法还是写一个可执行文件去测一下它的接口,看通没通就知道了;

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int ret= - 1 ;
  int pid = IPCThreadState::self()->getCallingPid();
 
    ALOGI( "demoNativeService client is now starting, pid=%d" , pid);
 
  android::sp sm = android::defaultServiceManager();
  android::sp binder;
  android::sp<idemonativeservice> shw;
 
  do {
          binder = sm->getService(android::String16( "ds.demonativeservice" ));
          if (binder != 0 )
                  break ;
          ALOGW( "IdemoNativeService not published, waiting..." );
          usleep( 500000 );
  } while ( true );
 
   ALOGI( "IdemoNativeService client is now trying" );
 
shw = android::interface_cast<idemonativeservice>(binder);
ret = shw->printString( "Good man desheng" );
   ALOGI( "demoNativeService client printString, ret=%d" , ret);
 
ret = shw->connect(pid, 1 , 2 , 3 , 4 );
   ALOGI( "demoNativeService client connect, ret=%d" , ret);</idemonativeservice></idemonativeservice></android::ibinder></android::iservicemanager>

 

下面就是笔者测试的打印,如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# dem
demoNativeServiceclient   demoNativeServiceserver  
# demoNativeServiceserver &                                                   
[ 2 ] 2332
# --------- beginning of /dev/log/main
02 - 19 17 : 10 : 57.890 E/HelloWorldService( 2332 ): demoNativeService created
 
#
# dem
demoNativeServiceclient   demoNativeServiceserver  
# demoNativeServiceclient                                                     
02 - 19 17 : 11 : 02.520 I/demoNativeService/Service( 2334 ): demoNativeService client is now starting, pid= 2334
02 - 19 17 : 11 : 02.520 I/demoNativeService/Service( 2334 ): IdemoNativeService client is now trying
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): OnTransact( 2 , 16 )
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): PrintString: Good man desheng
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): printString: Good man desheng
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): demoNativeService printString:Good man desheng
02 - 19 17 : 11 : 02.520 I/demoNativeService/Service( 2334 ): demoNativeService client printString, ret= 66
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): OnTransact( 1 , 16 )
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): CONNECT: 2334 , 1 , 2 , 3 , 4
02 - 19 17 : 11 : 02.520 D/HelloWorldService( 2332 ): demoNativeService connect: 2334 , 1 , 2 , 3 , 4
02 - 19 17 : 11 : 02.520 I/demoNativeService/Service( 2334 ): demoNativeService client connect, ret= 88
02 - 19 17 : 11 : 02.520 I/demoNativeService/Service( 2334 ): Hello client is now exiting
#
# 02 - 19 17 : 11 : 07.540 D/InitAlarmsService( 2259 ): Clearing and rescheduling alarms.
 
# service list
Found 78 services:
0   ds.demonativeservice: [android.hardware.IdemoNativeService]
1   phone: [com.android.internal.telephony.ITelephony]
2   iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]
3   simphonebook: [com.android.internal.telephony.IIccPhoneBook]
4   isms: [com.android.internal.telephony.ISms]
5   jeavoxmiddleware: [android.jeavox.IMiddleWareService]

 

写到这,如果要给应用调用的话,还需要写Client,JNI,JNI及以上在此不再讨论了,我们就简易来看看client怎么处理吧,其实有点类似上面那个可执行文件的写法,这里可能就是有一个对象的概念,可以保持,大概如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
demoNativeServiceClient::demoNativeServiceClient()
{
     sp<iservicemanager> sm = defaultServiceManager();
     sp<ibinder> binder = sm->getService(String16( "ds.demonativeservice" ));
     mdemoNativeService = interface_cast<idemonativeservice>(binder);
}
 
demoNativeServiceClient::~demoNativeServiceClient()
{
     mdemoNativeService = NULL;
}
 
int32_t demoNativeServiceClient::connect( int previewhw, int intf, int fmt, int chan)
{
     return mdemoNativeService->connect(getCallingPid(),previewhw,intf,fmt,chan);
}
 
int32_t demoNativeServiceClient::printString( const char *str)
{
    return mdemoNativeService->printString(str);
}</idemonativeservice></ibinder></iservicemanager>

 

罗哩罗嗦写了这么多,请大家拍砖,轻拍一下:)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值