大多是高老师的东西,我是边学边干,呵呵。话说Android还是1.5的时候......
一、
Android Service
介绍
Android
的
Service
分为两种:
Android Service
和
Native Service
。
Android Service
:又称为
Java Service
,是实现在框架层(
framework
)里的
Server
。
Android Service
以
Java
编写。
Native Service
:又称为
System Service
,是实现在
Runtime
层里的
Server
。
以
MediaPlayer
为例,从下图我们可以得出两种服务的关系:
接下来要讨论的
Service
是
Native Service
,与应用程序设计上所讨论的
Service
(
android.app.Service
)不同。
二、为什么要写底层的核心服务呢?
(
1
)
因为底层核心服务是
Android
框架里最接近
Linux/Driver
的部分。为了充分发挥硬件设备的差异化特性,核心服务是让上层
Java
应用程序来使用
Driver/HW Device
特色的重要管道。
(
2
)
在开机过程中,就可以启动核心服务
(
例如汉字输入法服务等
)
,让众多应用程序来共享之。
(
3
)
由于共享,所以能有效降低
Java
应用程序的大小
(Size)
。
三、如何实现一个核心服务呢
?
要点如下:
(
1
)核心服务通常在独立的进程
(Process)
里执行。
(
2
)必须提供
IBinder
接口,让应用程序可以进行跨进程的绑定
(Binding)
和呼叫。
(
3
)因为共享,所以必须确保多线裎安全
(Thread-safe)
。
(
4
)以
C++
类别定义,诞生其对象,透过
SM
之协助,将该对象参考值传给
IServiceManager::addService()
函数,就加入到
Binder Driver
里了。
(
5
)应用程序可透过
SM
之协助而远距绑定该核心服务,此时
SM
会回传
IBinder
接口给应用程序。
(
6
)应用程序可透过
IBinder::transact()
函数来与核心服务互传数据。
四、
Server
实现实践
下面以一个小例子来说明具体实现一个
Server
的步骤。此实例功能为简单的整数加法
(Add)
运算,我们将其命名
AddService
。
Step-1
:以
C++
撰写
AddService
类别,其完整程序代码为:
AddService.h
文件:
#ifndef ANDROID_GUILH_ADD_SERVICE_H
#define ANDROID_GUILH_ADD_SERVICE_H
#include <utils.h>
#include <utils/RefBase.h>
#include <utils/IInterface.h>
#include <utils/Parcel.h>
namespace android
{
class AddService : public BBinder
{
mutable Mutex mLock;
int32_t mNextConnId;
public:
static int instantiate();
AddService();
virtual ~AddService();
virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
};
}
#endif
AddService.cpp
文件:
#include "AddService.h"
#include <utils/IServiceManager.h>
#include <utils/IPCThreadState.h>
namespace android {
static struct sigaction oldact;
static pthread_key_t sigbuskey;
int AddService::instantiate() {
LOGE("AddService instantiate");
int r = defaultServiceManager()->addService(
String16("guilh.add"), new AddService());
LOGE("AddService r = %d/n", r);
return r;
}
AddService::AddService()
{ LOGV("AddService created");
mNextConnId = 1;
pthread_key_create(&sigbuskey, NULL);
}
AddService::~AddService()
{ pthread_key_delete(sigbuskey);
LOGV("AddService destroyed");
}
status_t AddService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
switch(code) {
case 0: {
pid_t pid = data.readInt32();
int num = data.readInt32();
num = num + 1000;
reply->writeInt32(num);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
};
Android.mk
文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= AddService.cpp
#LOCAL_C_INCLUDES:= $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES:= libutils
LOCAL_MODULE:= libAddService
LOCAL_PRELINK_MODULE:= false
include $(BUILD_SHARED_LIBRARY)
Step-2
:以
C++
撰写一个可独立执行的
addserver.cpp
程序,它的用途是:诞生一个
AddService
类别之对象,然后将该对象参考存入
Binder Driver
里。其内容为:
addserver.cpp
文件:
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <utils/IPCThreadState.h>
#include <utils/ProcessState.h>
#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
#include "../libaddservice/AddService.h"
using namespace android;
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
AddService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
Android.mk
文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= addserver.cpp
LOCAL_SHARED_LIBRARIES:= libutils libAddService
LOCAL_MODULE:= addservice
include $(BUILD_EXECUTABLE)
Step-3
:编译上述两个文件分别产出了
libAdd.so
类别库和
addserver
可执行程序。接着将
libAdd.so
拷贝到
Android
仿真器的
/system/lib/
里;也把
addserver
拷贝到
/system/bin/
里。
Step-4
:执行
addserver
。其中的指令:
AddServer::instantiate()
就执行到
AddServer
类别的
instantiate()
函数,其内容为:
int AddService::instantiate() {
LOGE("AddService instantiate");
int r = defaultServiceManager()->addService(
String16("guilh.add"), new AddService());
LOGE("AddService r = %d/n", r);
return r;
}
其先执行到
new AddServer()
,就诞生一个
AddServer
类别之对象;
接着,呼叫
defaultServiceManager()
函数取得
SM
的
IServiceManager
接口;
再呼叫
IServiceManager::addServer()
将该对象参考存入
Binder Driver
里。
Step-5
:这样就成功地将
AddService
服务加入到
Binder Driver
里了。现在就可以写个
Add
类来使用
AddService
核心服务了。以
C++
撰写
Add
类别,其完整程序代码为:
Add.h
文件:
#ifndef ANDROID _ADD_H
#define ANDROID _ADD_H
namespace android {
class Add {
public:
int setN(int n);
private:
static const void getAddService();
};
}; //namespace
#endif // ANDROID _ADD_H
Add.cpp
文件:
#include <utils/IServiceManager.h>
#include <utils/IPCThreadState.h>
#include "Add.h"
namespace android {
sp<IBinder> binder;
int Add::setN(int n){
getAddService();
Parcel data, reply;
data.writeInt32(getpid());
data.writeInt32(n);
LOGE("BpAddService::create remote()->transact()/n");
binder->transact(0, data, &reply);
int i = reply.readInt32();
return i;
}
const void Add::getAddService(){
sp<IServiceManager> sm = defaultServiceManager();
binder = sm->getService(String16("guilh.add"));
LOGE("Add::getAddService %p/n",sm.get());
if (binder == 0) {
LOGW("AddService not published, waiting...");
return;
}
}
};
Android.mk
文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=Add.cpp
LOCAL_SHARED_LIBRARIES := libutils libAddService
LOCAL_MODULE := libAdd
LOCAL_PRELINK_MODULE:= false
include $(BUILD_SHARED_LIBRARY)
Step-6
:下面写个
JNI Native
类别来使用
Add
类别之对象。透过
JNI Native
函数,就可以与
Java
层的
Service
服务衔接起来。
首选使用
javah
命令生成相应头文件。
com_hello_Service_MySer.h
文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hello_Service_MySer */
#ifndef _Included_com_hello_Service_MySer
#define _Included_com_hello_Service_MySer
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:
com_hello_Service_MySer
* Method:
intFromJNI
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_hello_Service_MySer_intFromJNI
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
然后实现相应函数。
com_hello_Service_MySer.cpp
文件:
#include <jni.h>
#include <JNIHelp.h>
#include "../libadd/Add.h"
#include "com_hello_Service_MySer.h"
JNIEXPORT jint JNICALL Java_com_hello_Service_MySer_intFromJNI(JNIEnv * env, jobject thiz)
{
android::Add myadd;
int r = myadd.setN(5);
return r;
}
Android.mk
文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)