Android(安卓)service
这里还有一编更详细的说明:
http://blog.csdn.net/maxleng/article/details/5490770
http://blog.csdn.net/21cnbao/article/details/8087328
Androidservice实现过程
一、AndroidService介绍
Android的Service分为三种:APP service、AndroidService和NativeService。
APP Service :为用户用java编译的后台服务程序。
AndroidService:又称为JavaService,是实现在框架层(framework)里的Server。AndroidService以Java编写。为Runtime提供管理级服务,比如systemService 、ManagerSerivce
NativeService:又称为SystemService,是实现在Runtime层里的Server。
以MediaPlayer为例,从下图我们可以得出两种服务的关系:
接下来要讨论的Service是NativeService,与应用程序设计上所讨论的Service(android.app.Service)不同。
二、为什么要写底层的核心服务呢?
(1)因为底层核心服务是Android框架里最接近Linux/Driver的部分。为了充分发挥硬件设备的差异化特性,核心服务是让上层Java应用程序来使用Driver/HWDevice特色的重要管道。
(2)在开机过程中,就可以启动核心服务(例如汉字输入法服务等),让众多应用程序来共享之。
(3)由于共享,所以能有效降低Java应用程序的大小(Size)。
三、如何实现一个核心服务呢?
要点如下:
(1)核心服务通常在独立的进程(Process)里执行。
(2)必须提供IBinder接口,让应用程序可以进行跨进程的绑定(Binding)和呼叫。
(3)因为共享,所以必须确保多线裎安全(Thread-safe)。
(4)以C++类别定义,诞生其对象,透过SM之协助,将该对象参考值传给IServiceManager::addService()函数,就加入到BinderDriver里了。
(5)应用程序可透过SM之协助而远距绑定该核心服务,此时SM会回传IBinder接口给应用程序。
(6)应用程序可透过IBinder::transact()函数来与核心服务互传数据。
四、Server实现实践
下面以一个小例子来说明具体实现一个Server的步骤。此实例功能为简单的整数加法(Add)运算,我们将其命名AddService。
Step-1:以C++撰写AddService类别,其完整程序代码为:
AddService.h文件:
#ifndefANDROID_GUILH_ADD_SERVICE_H
#defineANDROID_GUILH_ADD_SERVICE_H
#include<utils.h>
#include<utils/RefBase.h>
#include<utils/IInterface.h>
#include<utils/Parcel.h>
namespaceandroid
{
classAddService:publicBBinder
{
mutableMutexmLock;
int32_tmNextConnId;
public:
staticintinstantiate();
AddService();
virtual~AddService();
virtualstatus_tonTransact(uint32_t,constParcel&,Parcel*,uint32_t);
};
}
#endif
AddService.cpp文件:
#include"AddService.h"
#include<utils/IServiceManager.h>
#include<utils/IPCThreadState.h>
namespaceandroid{
staticstructsigactionoldact;
staticpthread_key_tsigbuskey;
intAddService::instantiate(){
LOGE("AddServiceinstantiate");
intr=defaultServiceManager()->addService(
String16("guilh.add"),newAddService());
LOGE("AddServicer=%d\n",r);
returnr;
}
AddService::AddService()
{LOGV("AddServicecreated");
mNextConnId=1;
pthread_key_create(&sigbuskey,NULL);
}
AddService::~AddService()
{pthread_key_delete(sigbuskey);
LOGV("AddServicedestroyed");
}
status_tAddService::onTransact(
uint32_tcode,constParcel&data,Parcel*reply,uint32_tflags){
switch(code){
case0:{
pid_tpid=data.readInt32();
intnum=data.readInt32();
num=num+1000;
reply->writeInt32(num);
returnNO_ERROR;
}break;
default:
returnBBinder::onTransact(code,data,reply,flags);
}
}
};
Android.mk文件:
LOCAL_PATH:=$(callmy-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类别之对象,然后将该对象参考存入BinderDriver里。其内容为:
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"
usingnamespaceandroid;
intmain(intargc,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:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_SRC_FILES:=addserver.cpp
LOCAL_SHARED_LIBRARIES:=libutilslibAddService
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()函数,其内容为:
intAddService::instantiate(){
LOGE("AddServiceinstantiate");
intr=defaultServiceManager()->addService(
String16("guilh.add"),newAddService());
LOGE("AddServicer=%d\n",r);
returnr;
}
其先执行到newAddServer(),就诞生一个AddServer类别之对象;
接着,呼叫defaultServiceManager()函数取得SM的IServiceManager接口;
再呼叫IServiceManager::addServer()将该对象参考存入BinderDriver里。
Step-5:这样就成功地将AddService服务加入到BinderDriver里了。现在就可以写个Add类来使用AddService核心服务了。以C++撰写Add类别,其完整程序代码为:
Add.h文件:
#ifndefANDROID_ADD_H
#defineANDROID_ADD_H
namespaceandroid{
classAdd{
public:
intsetN(intn);
private:
staticconstvoidgetAddService();
};
};//namespace
#endif//ANDROID_ADD_H
Add.cpp文件:
#include<utils/IServiceManager.h>
#include<utils/IPCThreadState.h>
#include"Add.h"
namespaceandroid{
sp<IBinder>binder;
intAdd::setN(intn){
getAddService();
Parceldata,reply;
data.writeInt32(getpid());
data.writeInt32(n);
LOGE("BpAddService::createremote()->transact()\n");
binder->transact(0,data,&reply);
inti=reply.readInt32();
returni;
}
constvoidAdd::getAddService(){
sp<IServiceManager>sm=defaultServiceManager();
binder=sm->getService(String16("guilh.add"));
LOGE("Add::getAddService%p\n",sm.get());
if(binder==0){
LOGW("AddServicenotpublished,waiting...");
return;
}
}
};
Android.mk文件:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_SRC_FILES:=Add.cpp
LOCAL_SHARED_LIBRARIES:=libutilslibAddService
LOCAL_MODULE:=libAdd
LOCAL_PRELINK_MODULE:=false
include$(BUILD_SHARED_LIBRARY)
Step-6:下面写个JNINative类别来使用Add类别之对象。透过JNINative函数,就可以与Java层的Service服务衔接起来。
首选使用javah命令生成相应头文件。
com_hello_Service_MySer.h文件:
/*DONOTEDITTHISFILE-itismachinegenerated*/
#include<jni.h>
/*Headerforclasscom_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
*/
JNIEXPORTjintJNICALLJava_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"
JNIEXPORTjintJNICALLJava_com_hello_Service_MySer_intFromJNI(JNIEnv*env,jobjectthiz)
{
android::Addmyadd;
intr=myadd.setN(5);
returnr;
}
Android.mk文件:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_SRC_FILES:=com_hello_Service_MySer.cpp
LOCAL_C_INCLUDES:=$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES:=libutilslibAdd
LOCAL_MODULE:=libJniAdd
LOCAL_PRELINK_MODULE:=false
include$(BUILD_SHARED_LIBRARY)
所有相关文件组织:
a@ubuntu:~/work/android/source_android/development/my_module$treeservice
service
|--addserver
||--Android.mk
|`--addserver.cpp
|--jni
||--Android.mk
||--com_hello_Service_MySer.cpp
|`--com_hello_Service_MySer.h
|--libadd
||--Add.cpp
||--Add.h
|`--Android.mk
`--libaddservice
|--AddService.cpp
|--AddService.h
`--Android.mk
4directories,11files
在Eclipse中创建一个工程使用以上的Add类,即可使用我们的AddService了。
MySer.java文件:
packagecom.hello.Service;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.TextView;
publicclassMySerextendsActivity{
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
inti=intFromJNI();
TextViewtv=newTextView(this);
tv.setText(String.valueOf(i));
setContentView(tv);
}
publicnativeintintFromJNI();
static{
System.loadLibrary("JniAdd");
}
}
五、Service编译问题
Android所用的Toolchain(即交叉编译工具链)可从下面的网址下载:
http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2。如果下载了完整的Android项目的源代码,则可以在“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下找到交叉编译工具,比如Android所用的arm-eabi-gcc-4.2.1。我们可以直接使用源码包来进行编译。
Android并没有采用glibc作为C库,而是采用了Google自己开发的BionicLibc,它的官方Toolchain也是基于BionicLibc而并非glibc的。这使得使用或移植其他Toolchain来用于Android要比较麻烦:在Google公布用于Android的官方Toolchain之前,多数的Android爱好者使用的Toolchain是在http://www.codesourcery.com/gnu_toolchains/arm/download.html下载的一个通用的Toolchain,它用来编译和移植Android的Linux内核是可行的,因为内核并不需要C库,但是开发Android的应用程序时,直接采用或者移植其他的Toolchain都比较麻烦,其他Toolchain编译的应用程序只能采用静态编译的方式才能运行于Android模拟器中,这显然是实际开发中所不能接受的方式。目前尚没有看到说明成功移植其他交叉编译器来编译Android应用程序的资料。
与glibc相比,BionicLibc有如下一些特点:
l采用BSDLicense,而不是glibc的GPLLicense;
l大小只有大约200k,比glibc差不多小一半,且比glibc更快;
l实现了一个更小、更快的pthread;
l提供了一些Android所需要的重要函数,如”getprop”,“LOGI”等;
l不完全支持POSIX标准,比如C++exceptions,widechars等;
l不提供libthread_db和libm的实现
另外,Android中所用的其他一些二进制工具也比较特殊:
加载动态库时使用的是/system/bin/linker而不是常用的/lib/ld.so;
prelink工具不是常用的prelink而是apriori,其源代码位于“<your_android>/build/tools/apriori”
strip工具也没有采用常用的strip,而是“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下的arm-eabi-strip,而是位于<your_android>/out/host/linux-x86/bin/的soslim工具。
下面就具体说一下如何编译我们刚才创建的Service程序。
1.在$(YOUR_ANDROID)/development目录下创建my_module目录,然后将我们的server文件夹拷贝到此目录下,其中$(YOUR_ANDROID)指Android源代码所在的目录。
#mkdir$(YOUR_ANDROID)/development/my_module
2.Android.mk这是AndroidMakefile的标准命名,不要更改。Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对Add程序的Android.mk文件内容如下:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_SRC_FILES:=Add.cpp
LOCAL_SHARED_LIBRARIES:=libutilslibAddService
LOCAL_MODULE:=libAdd
LOCAL_PRELINK_MODULE:=false
include$(BUILD_SHARED_LIBRARY)
注意上面LOCAL_SRC_FILES用来指定源文件;,LOCAL_MODULE指定要编译的模块的名字,下一步骤编译时就要用到;include$(BUILD_SHARED_LIBRARY)表示要编译成动态库,如果想编译成一个可执行文件则可用BUILD_EXECUTABLE,这些可以在$(YOUR_ANDROID)/build/core/config.mk查到。
3.回到Android源代码顶层目录进行编译:
#cd$(YOUR_ANDROID)&&makelibAdd
注意makelibAdd中的目标名libAdd就是上面Android.mk文件中由LOCAL_MODULE指定的模块名。
4.编译后的可执行文件存放在通过”adbpush”将它传送到模拟器上,再通过”adbshell”登录到模拟器终端,就可以执行了。
六、出现问题及及解决办法:
(1)提示缺bison,安装bison:sudoapt-getinstallbison
(2)出现frameworks/policies/base/PolicyConfig.mk:22:***NomoduledefinedforthegivenPRODUCT_POLICY(android.policy_phone).Stop.错误。
解决办法:
在build/tools/findleaves.sh中的第89行,
这一句find"${@:0:$nargs}"$findargs-typef-name"$filename"-print|
改为find"${@:1:$nargs-1}"$findargs-typef-name"$filename"-print|
更多相关文章
- 【翻译】(1)Android(安卓)NDK Overview
- Android编译过程详解(二)
- android studio 打包 so 库
- Android(安卓)Framework中添加AIDL文件编译
- Android(安卓)SDK下载和更新失败的解决方法!!!
- [Android交互]Android与Unity的交互
- android修改系统源码(重新编译源码)
- Android(安卓)input 输入系统学习
- android排版布局学习