当前位置: 代码迷 >> Android >> Android service 兑现过程
  详细解决方案

Android service 兑现过程

热度:15   发布时间:2016-05-01 13:43:20.0
Android service 实现过程

?

一、?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

?

  相关解决方案