一、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 中我们可以看到以下代码:
-
AlarmManagerService alarm = new AlarmManagerService (context );
-
ServiceManager .addService (Context .ALARM_SERVICE , alarm );
这个操作在系统启动时完成,由 ServiceManager 负责创建服务进程并运行之。
在目录/frameworks/base/core/java/android/app中IAlarmManager.aidl文件.
在目录frameworks/base/services/java/com/android/server中AlarmManagerService的aidl的实现类,
在目录frameworks/base/services/java/com/android/server增加 service的实现文件.
3.2.实验测试添加java 系统级服务步骤
3.2.1 增加aidl文件
在目录frameworks/base/core/java/android/app下增加中文件IDvbService.aidl.
-
package android.app;
-
-
interface IDvbService {
-
int countTest(in int testvalue);
-
}
3.2.2 创建服务类
在目录frameworks/base/services/java/com/android/server中增加DvbManagerService实现IDvbService.aidl类。
-
package com.android.server;
-
-
import android.content.Context;
-
import android.util.Slog;
-
import android.app.IDvbService;
-
-
class DvbManagerService extends IDvbService.Stub {
-
-
private static final String TAG = "DvbManagerService";
-
private static final boolean localLOGV = false;
-
-
private final Context mContext;
-
-
public DvbManagerService(Context context) {
-
super();
-
mContext = context;
-
Slog.w(TAG, "DvbManagerService");
-
}
-
-
public int countTest(int value){
-
return value*2;
-
}
-
-
}
3.2.3 将服务添加到ServiceManager
在文件 frameworks/base/services/java/com/android/server /SystemServer.java 类中run()方法中增加
-
try {
-
Slog.i(TAG, "Alarm DvbManagerService");
-
DvbManagerService dvb = new DvbManagerService(context);
-
ServiceManager.addService(Context.DVB_SERVICE, dvb);
-
} catch (Throwable e) {
-
reportWtf("starting DvbManagerService", e);
-
}
3.2.4 在Context中增加该服务对应的常量
在文件frameworks/base/core/java/android/content/Context.java中增加
-
public static final String DVB_SERVICE = "dvb";
3.2.5 在框架添加封装管理类
在文件frameworks/base/core/java/android/app中增加DvbManager.java
-
package android.app;
-
-
import android.content.Context;
-
import android.content.Intent;
-
import android.os.RemoteException;
-
import android.os.ServiceManager;
-
-
-
public class DvbManager{
-
private final IDvbService mService;
-
-
-
-
-
DvbManager(IDvbService service) {
-
mService = service;
-
}
-
-
-
public int count(int value) {
-
try {
-
return mService.countTest(value);
-
} catch (RemoteException ex) {
-
}
-
return -1;
-
}
-
}
3.2.6 增加获取封装管理类的方法
在文件frameworks/base/core/java/android/app/ContextImpl.java中新增加属性
-
private static DvbManager sDvbManager;
在getSystemService(String name)方法中增加
-
else if (DVB_SERVICE.equals(name)) {
-
return getDvbManager();
-
}
另外增加方法
-
private DvbManager getDvbManager() {
-
synchronized (sSync) {
-
if (sDvbManager == null) {
-
IBinder b = ServiceManager.getService(DVB_SERVICE);
-
IDvbService service = IDvbService.Stub.asInterface(b);
-
sDvbManager = new DvbManager(service);
-
}
-
}
-
return sDvbManager;
-
}
也可以不进行上述的两个操作而直接在static代码块里面添加。
-
registerService(ACCOUNT_SERVICE, new StaticServiceFetcher() {
-
public Object createService() {
-
IBinder b = ServiceManager.getService(DVB_SERVICE);
-
IAccountManager service = IAccountManager.Stub.asInterface(b);
-
return new DvbManager(service);
-
}});
Note :如果在封装的管理类中需要传入Context参数,如下,请看加粗部分的区别:
-
registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
-
public Object createService(ContextImpl ctx) {
-
IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
-
IAccountManager service = IAccountManager.Stub.asInterface(b);
-
return new AccountManager(ctx, service);
-
}});
3.2.7 在Android.mk里面进行配置
在frameworks/base/Android.mk中LOCAL_SRC_FILES += \ 下增加一行
-
core/java/android/app/IDvbService.aidl \
3.2.8 应用中调用
在应用调用如下:
导入import android.app.DvbManager;
用法
-
DvbManager dvb=(DvbManager)getSystemService(DVB_SERVICE);
-
int count = dvb.count(9);
-
Log.i(“DvbManager”,”count = ” + count ) ;
3.2.9 编译过程
编译如下:
(1)首先编译 frameworks
. build/envsetup.sh
choosecombo
make -j4 framework
编译后会生成framework.jar
(2)然后编译frameworks/base/services/java的service
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 头文件定义:
-
#ifndef __SERVICE_TEST_A__
-
#define __SERVICE_TEST_A__
-
-
#include
-
#include
-
#include
-
#include
-
-
namespace android{
-
-
class serviceTestA:public BBinder
-
{
-
public:
-
serviceTestA();
-
virtual ~serviceTestA();
-
static int instantiate();
-
virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
-
private:
-
-
mutable Mutex mLock;
-
};
-
}
-
#endif /* __SERVICE_TEST_A__ */
serviceTestA.cpp 实现文件:
-
#include
-
#include
-
#include
-
#include
-
#include
-
namespace android {
-
enum{
-
CALCULATE_MUL_NUM = 0,
-
CALCULATE_DIV_NUM ,
-
};
-
-
int serviceTestA::instantiate() {
-
LOGI("serviceTestA instantiate");
-
int r = defaultServiceManager()->addService(String16("service.TestA"),
-
new serviceTestA());
-
LOGI("serviceTestA r = %d/n", r);
-
return r;
-
}
-
-
serviceTestA::serviceTestA() {
-
LOGI("serviceTestA created");
-
}
-
-
serviceTestA::~serviceTestA(){
-
LOGI("serviceTestA destroyed");
-
}
-
-
status_t serviceTestA::onTransact(uint32_t code, const Parcel&data, Parcel*reply, uint32_t flags){
-
LOGI("serviceTestA::onTransact code = %d",code);
-
Mutex::Autolock _l(mLock);
-
switch(code){
-
case CALCULATE_MUL_NUM:{
-
int a = data.readInt32();
-
int b = data.readInt32();
-
int sum = a * b ;
-
LOGI("sum mul value = %d",sum);
-
reply->writeInt32(sum);
-
return NO_ERROR;
-
}
-
break;
-
case CALCULATE_DIV_NUM:{
-
int a = data.readInt32();
-
int b = data.readInt32();
-
int sum = a / b ;
-
LOGI("sum div value = %d",sum);
-
reply->writeInt32(sum);
-
return NO_ERROR;
-
}
-
break;
-
default:
-
return BBinder::onTransact(code, data, reply, flags);
-
}
-
return 0;
-
}
-
}
Android.mk 文件:
-
LOCAL_PATH:= $(call my-dir)
-
include $(CLEAR_VARS)
-
LOCAL_SRC_FILES:= serviceTestA.cpp
-
LOCAL_SHARED_LIBRARIES:= libutils libutils libbinder
-
LOCAL_C_INCLUDES := $(TOP)/frameworks/base/include
-
LOCAL_MODULE:= libServiceTestA
-
LOCAL_PRELINK_MODULE:= false
-
include $(BUILD_SHARED_LIBRARY)
这里生成libServiceTestA动态库,方例升级服务程序
编写独立的进程程序:
它的用途是:诞生一个 serviceTestA 类别之对象,然后将该对象参考存入 Binder Driver 里。
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
using namespace android;
-
-
int main(int argc,char *argv[]){
-
sp proc(ProcessState::self());
-
sp sm = defaultServiceManager();
-
LOGI("ServiceManager: %p", sm.get());
-
serviceTestA::instantiate();
-
ProcessState::self()->startThreadPool();
-
IPCThreadState::self()->joinThreadPool();
-
return 0;
-
}
Android.mk 文件:
-
LOCAL_PATH:= $(call my-dir)
-
include $(CLEAR_VARS)
-
LOCAL_SRC_FILES:= main.cpp
-
LOCAL_SHARED_LIBRARIES:= libutils libServiceTestA
-
LOCAL_MODULE:= serviceTestA
-
include $(BUILD_EXECUTABLE)
这里最重要的是调用:serviceTestA::instantiate();
其先执行到 new serviceTestA() ,就诞生一个 serviceTestA 类别之对象;
接着,呼叫 defaultServiceManager() 函数取得 SM 的 IServiceManager 接口;
再呼叫 IServiceManager::addService() 将该对象参考存入 Binder Driver 里,并且同时存入
到ServiceManager中注册并管理,如此其它进程才能通过ServiceManager::getService找到相应服务进程
以上代码同理,serviceTestB服务进程也一样的这样建立,不再复述。
4.2 测试服务进程
testService.cpp编写:
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
using namespace android;
-
-
enum{
-
CALCULATE_ADD_NUM = 0,
-
CALCULATE_SUB_NUM ,
-
};
-
-
enum{
-
CALCULATE_MUL_NUM = 0,
-
CALCULATE_DIV_NUM ,
-
};
-
-
int main(int argc,char *argv[]){
-
sp TestAbinder;
-
sp TestBbinder;
-
Parcel data, reply;
-
int sum=0;
-
LOGI("testService main is call...");
-
sp sm = defaultServiceManager();
-
-
while(1){
-
TestAbinder = sm->getService(String16("service.TestA"));
-
LOGE("TestA::getAddService %p/n",sm.get());
-
if (TestAbinder == 0) {
-
LOGE("TestAService not published, waiting...");
-
usleep(1000000);
-
continue;
-
}
-
else{
-
LOGI("TestA::getAddService success...");
-
break;
-
}
-
}
-
-
while(1){
-
TestBbinder = sm->getService(String16("service.TestB"));
-
LOGE("TestB::getAddService %p/n",sm.get());
-
if (TestBbinder == 0) {
-
LOGE("TestBService not published, waiting...");
-
usleep(1000000);
-
continue;
-
}
-
else{
-
LOGI("TestB::getAddService success...");
-
break;
-
}
-
}
-
-
-
data.writeInt32(1000);
-
data.writeInt32(200);
-
LOGI("BpAddService::create remote()->transact()/n");
-
TestAbinder->transact(CALCULATE_MUL_NUM,data,&reply);
-
sum = reply.readInt32();
-
LOGI("CALCULATE_ADD_NUM value = %d",sum);
-
-
data.writeInt32(1000);
-
data.writeInt32(200);
-
LOGI("BpAddService::create remote()->transact()/n");
-
TestAbinder->transact(CALCULATE_DIV_NUM,data,&reply);
-
sum = reply.readInt32();
-
LOGI("CALCULATE_SUB_NUM value = %d",sum);
-
-
data.writeInt32(1000);
-
data.writeInt32(200);
-
LOGI("BpAddService::create remote()->transact()/n");
-
TestBbinder->transact(CALCULATE_ADD_NUM,data,&reply);
-
sum = reply.readInt32();
-
LOGI("CALCULATE_MUL_NUM value = %d",sum);
-
-
data.writeInt32(1000);
-
data.writeInt32(200);
-
LOGI("BpAddService::create remote()->transact()/n");
-
TestBbinder->transact(CALCULATE_SUB_NUM,data,&reply);
-
sum = reply.readInt32();
-
LOGI("CALCULATE_DIV_NUM value = %d",sum);
-
-
return 0;
-
}
这里最重要的就是通过defaultServiceManager得到默认的sm,然后通过getService得到sp对象,即可操作相应服务进程的接口函数,整个过程还是相当清晰的。
最后附上测试的结果打印:
-
# ./TestService
-
./TestService
-
# logcat
-
logcat
-
--------- beginning of /dev/log/main
-
I/ ( 1379): testService main is call...
-
E/ ( 1379): TestA::getAddService 0xa680/n
-
I/ ( 1379): TestA::getAddService success...
-
E/ ( 1379): TestB::getAddService 0xa680/n
-
I/ ( 1379): TestB::getAddService success...
-
I/ ( 1379): BpAddService::create remote()->transact()/n
-
I/ ( 1371): serviceTestA::onTransact code = 0
-
I/ ( 1371): sum mul value = 200000
-
I/ ( 1379): CALCULATE_MUL_NUM value = 200000
-
I/ ( 1379): BpAddService::create remote()->transact()/n
-
I/ ( 1371): serviceTestA::onTransact code = 1
-
I/ ( 1371): sum div value = 5
-
I/ ( 1379): CALCULATE_DIV_NUM value = 5
-
I/ ( 1379): BpAddService::create remote()->transact()/n
-
I/ ( 1374): serviceTestB::onTransact code = 0
-
I/ ( 1374): sum add value = 1200
-
I/ ( 1379): CALCULATE_ADD_NUM value = 1200
-
I/ ( 1379): BpAddService::create remote()->transact()/n
-
I/ ( 1374): serviceTestB::onTransact code = 1
-
I/ ( 1374): sum sub value = 800
-
I/ ( 1379): CALCULATE_SUB_NUM value = 800
结果表明完全正确
文章转自
阅读(962) | 评论(0) | 转发(0) |