这里还有一编更详细的说明:

http://blog.csdn.net/maxleng/article/details/5490770

http://blog.csdn.net/21cnbao/article/details/8087328

Androidservice实现过程

一、AndroidService介绍

AndroidService分为三种:APP serviceAndroidServiceNativeService

APP Service :为用户用java编译的后台服务程序。

AndroidService:又称为JavaService,是实现在框架层(framework)里的ServerAndroidService以Java编写。为Runtime提供管理级服务,比如systemService 、ManagerSerivce

NativeService:又称为SystemService,是实现在Runtime层里的Server

MediaPlayer为例,从下图我们可以得出两种服务的关系:

接下来要讨论的ServiceNativeService,与应用程序设计上所讨论的Serviceandroid.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()函数取得SMIServiceManager接口;

再呼叫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,它用来编译和移植AndroidLinux内核是可行的,因为内核并不需要C库,但是开发Android的应用程序时,直接采用或者移植其他的Toolchain都比较麻烦,其他Toolchain编译的应用程序只能采用静态编译的方式才能运行于Android模拟器中,这显然是实际开发中所不能接受的方式。目前尚没有看到说明成功移植其他交叉编译器来编译Android应用程序的资料。

glibc相比,BionicLibc有如下一些特点:

l采用BSDLicense,而不是glibcGPLLicense

l大小只有大约200k,比glibc差不多小一半,且比glibc更快;

l实现了一个更小、更快的pthread

l提供了一些Android所需要的重要函数,如”getprop,LOGI”等;

l不完全支持POSIX标准,比如C++exceptionswidechars等;

l不提供libthread_dblibm的实现

另外,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,安装bisonsudoapt-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. 【翻译】(1)Android(安卓)NDK Overview
  2. Android编译过程详解(二)
  3. android studio 打包 so 库
  4. Android(安卓)Framework中添加AIDL文件编译
  5. Android(安卓)SDK下载和更新失败的解决方法!!!
  6. [Android交互]Android与Unity的交互
  7. android修改系统源码(重新编译源码)
  8. Android(安卓)input 输入系统学习
  9. android排版布局学习

随机推荐

  1. 为Android安装BusyBox
  2. Android 中的DisplayMetrics的用法
  3. 编程回忆之Android回忆(有关Android 列表
  4. Android GridView选择样式
  5. 【转】修改Android应用程序的默认最大内
  6. 在Android中实现service动态更新UI界面
  7. Android ListView,GridView,ScrollView,P
  8. android jni开发环境的搭建
  9. [置顶] Android中在界面上动态显示歌词
  10. Android 异步更新UI----AsyncTask