?
一、?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); };}#endifAddService.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_Hnamespace 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 __cplusplusextern "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) LOCAL_SRC_FILES:=com_hello_Service_MySer.cpp LOCAL_C_INCLUDES:= $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := libutils libAdd LOCAL_MODULE := libJniAdd LOCAL_PRELINK_MODULE:= false include $(BUILD_SHARED_LIBRARY)?
?
所有相关文件组织:
[email protected]:~/work/android/source_android/development/my_module$ tree service
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
?
4 directories, 11 files
在?Eclipse?中创建一个工程使用以上的?Add?类,即可使用我们的?AddService?了。
MySer.java?文件:
?
package com.hello.Service; import android.app.Activity;import android.os.Bundle;import android.widget.TextView; public class MySer extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int i = intFromJNI(); TextView tv = new TextView(this); tv.setText( String.valueOf(i) ); setContentView(tv); } public native int intFromJNI(); 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?自己开发的?Bionic Libc?,它的官方?Toolchain?也是基于Bionic Libc?而并非?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?相比,?Bionic Libc?有如下一些特点:
l?????????采用?BSD License?,而不是?glibc?的?GPL License?;
l?????????大小只有大约?200k?,比?glibc?差不多小一半,且比?glibc?更快;
l?????????实现了一个更小、更快的?pthread?;
l?????????提供了一些?Android?所需要的重要函数,如”?getprop?”?,?“?LOGI?”等;
l?????????不完全支持?POSIX?标准,比如?C++ exceptions?,?wide chars?等;
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?这是?Android Makefile?的标准命名,不要更改。?Android.mk?文件的格式和内容可以参考其他已有的Android.mk?文件的写法,针对?Add?程序的?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)?
?
注意上面?LOCAL_SRC_FILES?用来指定源文件;,?LOCAL_MODULE?指定要编译的模块的名字,下一步骤编译时就要用到;?include $(BUILD_SHARED_LIBRARY)?表示要编译成动态库,如果想编译成一个可执行文件则可用BUILD_EXECUTABLE?,这些可以在?$(YOUR_ANDROID)/build/core/config.mk?查到。
?
3.?回到?Android?源代码顶层目录进行编译:
# cd $(YOUR_ANDROID) && make libAdd
注意?make libAdd?中的目标名?libAdd?就是上面?Android.mk?文件中由?LOCAL_MODULE?指定的模块名。
4?.编译后的可执行文件存放在通过”?adb push?”将它传送到模拟器上,再通过”?adb shell?”登录到模拟器终端,就可以执行了。
?
六、出现问题及及解决办法:
?
(?1?)提示缺?bison?,安装?bison?:?sudo apt-get install bison
(?2?)出现?frameworks/policies/base/PolicyConfig.mk:22: *** No module defined for the given PRODUCT_POLICY (android.policy_phone).??Stop.?错误。
解决办法:
在?build/tools/findleaves.sh?中的第?89?行,
这一句?find "${@:0:$nargs}" $findargs -type f -name "$filename" -print |
改为?find "${@:1:$nargs-1}" $findargs -type f -name "$filename" -print |
转载:http://blog.chinaunix.net/u/22630/article_105768.html
?