Chinaunix首页 | 论坛 | 博客
  • 博客访问: 134912
  • 博文数量: 34
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 700
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-12 16:52
文章分类

全部博文(34)

文章存档

2015年(13)

2014年(21)

我的朋友

分类: Android平台

2015-01-23 15:13:35

一、android 系统级 service简要说明

 

android系统级的服务包含了Android Service Native Service .

 

Android Service 也称作 Java Service ,是用JAVA语言编写的,实现在框架层。

Native Service 也称作 System Service ,是用C++语言编写的,实现在Runtime层。

 

对于这两种service来说,两个对等service通讯都是利用binder,只不过一种利用*.aidl,一种利用IInterface编写序列化代码而已,本质是一样的,下面先介绍native service的编写及两个native service如何通讯的过程。

 

二、native service的特点

 

A、因为底层核心服务是 Android 框架里最接近 Linux/Driver 的部分。为了充分发挥硬件设备的差异化特性,核心服务是让上层 Java 应用程序来使用 Driver/HW Device 特色的重要管道。

B、在开机过程中,就可以启动核心服务 例如汉字输入法服务等 ,让众多应用程序来共享之。

C、由于共享,所以能有效降低程序的大小及统一的接口变化 。

 

.如何实现一个Android service 

 

3.1.以 AlarmManagerService为例进行说明

 

Java层服务顾名思义即为从 Java层提供的服务,它与 C++层的服务不同之处在于其服务进程的运行由系统( ServiceManager)统一维护。在文件 frameworks/base/services/java/com/android/server/SystemServer.java 中我们可以看到以下代码:


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. AlarmManagerService alarm = new AlarmManagerService (context );  
  2. ServiceManager .addService (Context .ALARM_SERVICE , alarm );  


这个操作在系统启动时完成,由 ServiceManager 负责创建服务进程并运行之。

在目录/frameworks/base/core/java/android/appIAlarmManager.aidl文件.

在目录frameworks/base/services/java/com/android/serverAlarmManagerServiceaidl的实现类,

在目录frameworks/base/services/java/com/android/server增加 service的实现文件.

3.2.实验测试添加java 系统级服务步骤

3.2.1 增加aidl文件

在目录frameworks/base/core/java/android/app下增加中文件IDvbService.aidl.


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package android.app;  
  2.   
  3. interface IDvbService {  
  4.     int countTest(in int testvalue);  
  5. }  


3.2.2 创建服务类

在目录frameworks/base/services/java/com/android/server中增加DvbManagerService实现IDvbService.aidl

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.android.server;  
  2.   
  3. import android.content.Context;  
  4. import android.util.Slog;  
  5. import android.app.IDvbService;  
  6.   
  7. class DvbManagerService extends IDvbService.Stub {  
  8.    
  9.     private static final String TAG = "DvbManagerService";  
  10.     private static final boolean localLOGV = false;  
  11.   
  12.     private final Context mContext;  
  13.       
  14.     public DvbManagerService(Context context) {  
  15.         super();  
  16.         mContext = context;  
  17.         Slog.w(TAG, "DvbManagerService");  
  18.     }  
  19.       
  20.     public int countTest(int value){  
  21.         return value*2;  
  22.     }  
  23.       
  24. }  


3.2.3 将服务添加到ServiceManager

在文件 frameworks/base/services/java/com/android/server /SystemServer.java 类中run()方法中增加

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. try {  
  2. Slog.i(TAG, "Alarm DvbManagerService");  
  3. DvbManagerService dvb = new DvbManagerService(context);  
  4. ServiceManager.addService(Context.DVB_SERVICE, dvb);    
  5. catch (Throwable e) {  
  6.      reportWtf("starting DvbManagerService", e);  
  7. }  


3.2.4 Context中增加该服务对应的常量

在文件frameworks/base/core/java/android/content/Context.java中增加


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static final String DVB_SERVICE = "dvb";//dvb  


3.2.5 在框架添加封装管理类

在文件frameworks/base/core/java/android/app中增加DvbManager.java


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package android.app;  
  2.   
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5. import android.os.RemoteException;  
  6. import android.os.ServiceManager;  
  7.   
  8.   
  9. public class DvbManager{  
  10.     private final IDvbService mService;  
  11.   
  12.     /** 
  13.      * package private on purpose 
  14.      */  
  15.     DvbManager(IDvbService service) {  
  16.         mService = service;  
  17.     }  
  18.       
  19.   
  20.     public int count(int value) {  
  21.         try {  
  22.             return mService.countTest(value);  
  23.         } catch (RemoteException ex) {  
  24.         }  
  25.         return -1;  
  26.     }      
  27. }  


3.2.6 增加获取封装管理类的方法

在文件frameworks/base/core/java/android/app/ContextImpl.java中新增加属性


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private static DvbManager sDvbManager;//dvb  


getSystemService(String name)方法中增加


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. else if (DVB_SERVICE.equals(name)) {//dvb  
  2. return getDvbManager();  
  3. }   


另外增加方法


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private DvbManager getDvbManager() {//dvb  
  2.     synchronized (sSync) {  
  3.         if (sDvbManager == null) {  
  4.             IBinder b = ServiceManager.getService(DVB_SERVICE);  
  5.             IDvbService service = IDvbService.Stub.asInterface(b);  
  6.             sDvbManager = new DvbManager(service);  
  7.         }  
  8.     }  
  9.     return sDvbManager;  
  10. }  


也可以不进行上述的两个操作而直接在static代码块里面添加。


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. registerService(ACCOUNT_SERVICE, new StaticServiceFetcher() {  
  2. public Object createService() {  
  3. IBinder b = ServiceManager.getService(DVB_SERVICE);  
  4. IAccountManager service = IAccountManager.Stub.asInterface(b);  
  5. return new DvbManager(service);  
  6. }});  


Note :如果在封装的管理类中需要传入Context参数,如下,请看加粗部分的区别:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. registerService(ACCOUNT_SERVICE, new ServiceFetcher() {  
  2. public Object createService(ContextImpl ctx) {  
  3. IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);  
  4. IAccountManager service = IAccountManager.Stub.asInterface(b);  
  5. return new AccountManager(ctx, service);  
  6. }});  


3.2.7 Android.mk里面进行配置

frameworks/base/Android.mkLOCAL_SRC_FILES += \ 下增加一行


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. core/java/android/app/IDvbService.aidl \  


3.2.8 应用中调用

在应用调用如下:

导入import android.app.DvbManager;

用法


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. DvbManager dvb=(DvbManager)getSystemService(DVB_SERVICE);  
  2. int count = dvb.count(9);  
  3. Log.i(“DvbManager”,”count = ” + count ) ;  


3.2.9 编译过程

编译如下:

1)首先编译 frameworks

. build/envsetup.sh 

choosecombo 

make -j4  framework

编译后会生成framework.jar

2)然后编译frameworks/base/services/javaservice

make -j4  frameworks/base/services/java

编译后会生成services.jar

3)编译应用

因为服务是自定义的,所有必须在自定义的sdk中编译才能使用。

四、如何实现一个native service

要点如下:

a、核心服务通常在独立的进程 (Process) 里执行。

b、必须提供 IBinder 接口,让其它程序可以进行跨进程的绑定 (Binding) 和呼叫。

c、因为共享,所以必须确保多线程安全 (Thread-safe) 

d、以 C++ 类别定义,诞生其对象,透过 SM 之协助,将该对象参考值传给 IServiceManager::addService() 函数,就加入到 Binder Driver 里了。

e、应用程序可透过 SM 之协助而远距绑定该核心服务,此时 SM 会回传 IBinder 接口给应用程序。

f、应用程序可透过 IBinder::transact() 函数来与核心服务互传数据。

 

下面以具体实例讲解一下具体的每个步骤如何实现完成

先说明一个测试例子的模块结构:

 

serviceTestA 是一个普通的过程,提供两个整数的乘法及除法运算

serviceTestB 是一个普通的过程,提供两个整数的加法及减法运算

TestService 是一个测试进程的程序,主要验证两个服务进程的接口函数,其中的代码可以放在任何一个进程进行访问调用

 

4.1 编写服务进程

serviceTestA.h 头文件定义:


  1. #ifndef __SERVICE_TEST_A__  
  2. #define __SERVICE_TEST_A__  
  3.   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. namespace android{  
  10. //继承BBinder类,从而提供IBinder 接口  
  11. class serviceTestA:public BBinder  
  12. {  
  13. public:  
  14.             serviceTestA();  
  15. virtual ~serviceTestA();  
  16. static int instantiate(); //建立唯一类实例  
  17. virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);  
  18. private:  
  19. // protected by mLock 多线程安全  
  20. mutable Mutex mLock;  
  21. };  
  22. }  
  23. #endif /* __SERVICE_TEST_A__ */  


serviceTestA.cpp 实现文件:


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. namespace android {  
  7.     enum{  
  8.         CALCULATE_MUL_NUM = 0,  
  9.         CALCULATE_DIV_NUM ,  
  10.     };  
  11.   
  12.     int serviceTestA::instantiate() {  
  13.         LOGI("serviceTestA instantiate");  
  14.         int r = defaultServiceManager()->addService(String16("service.TestA"),  
  15.         new serviceTestA());  
  16.         LOGI("serviceTestA r = %d/n", r);  
  17.         return r;  
  18.     }  
  19.   
  20.     serviceTestA::serviceTestA() {  
  21.         LOGI("serviceTestA created");  
  22.     }  
  23.   
  24.     serviceTestA::~serviceTestA(){  
  25.         LOGI("serviceTestA destroyed");  
  26.     }  
  27.   
  28.     status_t serviceTestA::onTransact(uint32_t code, const Parcel&data, Parcel*reply, uint32_t flags){  
  29.         LOGI("serviceTestA::onTransact code = %d",code);  
  30.         Mutex::Autolock _l(mLock);  
  31.         switch(code){  
  32.             case CALCULATE_MUL_NUM:{  
  33.                     int a = data.readInt32();  
  34.                     int b = data.readInt32();  
  35.                     int sum = a * b ;  
  36.                     LOGI("sum mul value = %d",sum);  
  37.                     reply->writeInt32(sum);  
  38.                     return NO_ERROR;  
  39.                 }  
  40.                 break;  
  41.             case CALCULATE_DIV_NUM:{  
  42.                 int a = data.readInt32();  
  43.                 int b = data.readInt32();  
  44.                 int sum = a / b ;  
  45.                 LOGI("sum div value = %d",sum);  
  46.                 reply->writeInt32(sum);  
  47.                 return NO_ERROR;  
  48.             }  
  49.                 break;  
  50.             default:  
  51.                 return BBinder::onTransact(code, data, reply, flags);  
  52.         }  
  53.         return 0;  
  54.     }  
  55. }  


Android.mk 文件:


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)   
  3. LOCAL_SRC_FILES:= serviceTestA.cpp  
  4. LOCAL_SHARED_LIBRARIES:= libutils libutils libbinder  
  5. LOCAL_C_INCLUDES := $(TOP)/frameworks/base/include  
  6. LOCAL_MODULE:= libServiceTestA  
  7. LOCAL_PRELINK_MODULE:= false  
  8. include $(BUILD_SHARED_LIBRARY)  


这里生成libServiceTestA动态库,方例升级服务程序

编写独立的进程程序:

它的用途是:诞生一个 serviceTestA 类别之对象,然后将该对象参考存入 Binder Driver 里。


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7.   
  8. using namespace android;  
  9.   
  10. int main(int argc,char *argv[]){  
  11. sp proc(ProcessState::self());  
  12. sp sm = defaultServiceManager();  
  13. LOGI("ServiceManager: %p", sm.get());  
  14. serviceTestA::instantiate(); // 这是重点。。。。  
  15. ProcessState::self()->startThreadPool();  
  16. IPCThreadState::self()->joinThreadPool();  
  17. return 0;  
  18. }  


Android.mk 文件:


  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_SRC_FILES:= main.cpp  
  4. LOCAL_SHARED_LIBRARIES:= libutils libServiceTestA  
  5. LOCAL_MODULE:= serviceTestA  
  6. include $(BUILD_EXECUTABLE)  


这里最重要的是调用:serviceTestA::instantiate();

其先执行到 new serviceTestA() ,就诞生一个 serviceTestA 类别之对象;

接着,呼叫 defaultServiceManager() 函数取得 SM 的 IServiceManager 接口;

再呼叫 IServiceManager::addService() 将该对象参考存入 Binder Driver 里,并且同时存入

ServiceManager中注册并管理,如此其它进程才能通过ServiceManager::getService找到相应服务进程

以上代码同理,serviceTestB服务进程也一样的这样建立,不再复述。

4.2 测试服务进程

 

testService.cpp编写:


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7.   
  8. using namespace android;  
  9.   
  10. enum{  
  11. CALCULATE_ADD_NUM = 0,  
  12. CALCULATE_SUB_NUM ,  
  13. };  
  14.   
  15. enum{  
  16. CALCULATE_MUL_NUM = 0,  
  17. CALCULATE_DIV_NUM ,  
  18. };  
  19.   
  20. int main(int argc,char *argv[]){  
  21. sp TestAbinder;  
  22. sp TestBbinder;  
  23. Parcel data, reply;  
  24. int sum=0;  
  25. LOGI("testService main is call...");  
  26. sp sm = defaultServiceManager();  
  27.   
  28. while(1){  
  29. TestAbinder = sm->getService(String16("service.TestA"));  
  30. LOGE("TestA::getAddService %p/n",sm.get());  
  31. if (TestAbinder == 0) {  
  32. LOGE("TestAService not published, waiting...");  
  33. usleep(1000000);  
  34. continue;  
  35. }  
  36. else{  
  37. LOGI("TestA::getAddService success...");  
  38. break;  
  39. }     
  40. }  
  41.   
  42. while(1){  
  43. TestBbinder = sm->getService(String16("service.TestB"));  
  44. LOGE("TestB::getAddService %p/n",sm.get());  
  45. if (TestBbinder == 0) {  
  46. LOGE("TestBService not published, waiting...");  
  47. usleep(1000000);  
  48. continue;  
  49. }  
  50. else{  
  51. LOGI("TestB::getAddService success...");  
  52. break;  
  53. }  
  54. }  
  55.   
  56. //测试两个service中的函数  
  57. data.writeInt32(1000);  
  58. data.writeInt32(200);  
  59. LOGI("BpAddService::create remote()->transact()/n");  
  60. TestAbinder->transact(CALCULATE_MUL_NUM,data,&reply);  
  61. sum = reply.readInt32();  
  62. LOGI("CALCULATE_ADD_NUM value = %d",sum);  
  63.   
  64. data.writeInt32(1000);  
  65. data.writeInt32(200);  
  66. LOGI("BpAddService::create remote()->transact()/n");  
  67. TestAbinder->transact(CALCULATE_DIV_NUM,data,&reply);  
  68. sum = reply.readInt32();  
  69. LOGI("CALCULATE_SUB_NUM value = %d",sum);  
  70.   
  71. data.writeInt32(1000);  
  72. data.writeInt32(200);  
  73. LOGI("BpAddService::create remote()->transact()/n");  
  74. TestBbinder->transact(CALCULATE_ADD_NUM,data,&reply);  
  75. sum = reply.readInt32();  
  76. LOGI("CALCULATE_MUL_NUM value = %d",sum);  
  77.   
  78. data.writeInt32(1000);  
  79. data.writeInt32(200);  
  80. LOGI("BpAddService::create remote()->transact()/n");  
  81. TestBbinder->transact(CALCULATE_SUB_NUM,data,&reply);  
  82. sum = reply.readInt32();  
  83. LOGI("CALCULATE_DIV_NUM value = %d",sum);  
  84.   
  85. return 0;  
  86. }  


这里最重要的就是通过defaultServiceManager得到默认的sm,然后通过getService得到sp对象,即可操作相应服务进程的接口函数,整个过程还是相当清晰的。

最后附上测试的结果打印:


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. # ./TestService  
  2. ./TestService  
  3. # logcat  
  4. logcat  
  5. --------- beginning of /dev/log/main  
  6. I/        ( 1379): testService main is call...  
  7. E/        ( 1379): TestA::getAddService 0xa680/n  
  8. I/        ( 1379): TestA::getAddService success...  
  9. E/        ( 1379): TestB::getAddService 0xa680/n  
  10. I/        ( 1379): TestB::getAddService success...  
  11. I/        ( 1379): BpAddService::create remote()->transact()/n  
  12. I/        ( 1371): serviceTestA::onTransact code = 0  
  13. I/        ( 1371): sum mul value = 200000  
  14. I/        ( 1379): CALCULATE_MUL_NUM value = 200000  
  15. I/        ( 1379): BpAddService::create remote()->transact()/n  
  16. I/        ( 1371): serviceTestA::onTransact code = 1  
  17. I/        ( 1371): sum div value = 5  
  18. I/        ( 1379): CALCULATE_DIV_NUM value = 5  
  19. I/        ( 1379): BpAddService::create remote()->transact()/n  
  20. I/        ( 1374): serviceTestB::onTransact code = 0  
  21. I/        ( 1374): sum add value = 1200  
  22. I/        ( 1379): CALCULATE_ADD_NUM value = 1200  
  23. I/        ( 1379): BpAddService::create remote()->transact()/n  
  24. I/        ( 1374): serviceTestB::onTransact code = 1  
  25. I/        ( 1374): sum sub value = 800  
  26. I/        ( 1379): CALCULATE_SUB_NUM value = 800  



结果表明完全正确
文章转自

阅读(962) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~