Android本地服务编写实践
来源:互联网 发布:电脑程序员工资多少 编辑:程序博客网 时间:2024/05/22 00:31
在android系统中服务是个非常常见的东东,平台的各个层次都有服务这个概念。一开始接触是有点头晕的,不过循序渐进的学习,理清思路还是很有必要的。本地层的服务涉及最广,也最具代表性,今天就先编写个本地层的服务。 android中media类的服务就属于本地层中的服务了,服务使用C/C++实现,一般是一个可执行的二进制文件放在 /system/bin/目录下,由init.rc脚本开机启动, 运用层通过jni+binder来调用。下面我来写个简单的本地层服务CustomNativeService, 然后实现一个android.myservice.CustonNativeService的API类给运用层调用。 写一个服务,首先要搞清楚这个服务提供什么功能,也就是服务接口,这个很关键。CustomNativeService提供一个getState()的服务接口,知道这个后我们实现服务 的接口类ICustomNativeService, 包含一个头文件ICustomNativeService.h ,一个实现文件ICustonNativeService.cpp 。并同时实现binder通信的Bn端和Bp端,然后实现 服务的本地部分CustomNativeService.cpp ,生成可执行文件CustomNativeService。文件层次为:--external\myservice\CustomNativeService\ --common\ --ICustomNativeService.h --ICustomNativeService.cpp --CustomNativeService.cpp --Android.mk ICustomNativeService.h代码: #ifndef ICUSTOM_NATIVE_SERVICE_H #define ICUSTOM_NATIVE_SERVICE_H #include<utils/RefBase.h> #include<binder/IInterface.h> #include<binder/Parcel.h> using namespace android; //命名空间别搞错,否则编译不过 class ICustomNativeService : public IInterface { public : //这些声明是public的,这个很关键 DECLARE_META_INTERFACE(CustomNativeService); //这个宏主要为接口类声明了一个descriptor属性和一个asInterface方法 virtual int32_t getState() = 0; //声明我们要提供服务接口 }; /* 下面声明调用服务binder通信时的Bn端,Binder通信时,Bn端为服务的桩(Stub),实现BBinder接口(主要是OnTransact方法)。Bp端为客户端代理, 实现IBinder接口(主要是Transact方法)。每次通信都是客户端调用IBinder的Transact方法,同时触发服务端BBinder的onTransact方法的调用。 */ class BnCustomNativeService : public BnInterface<ICustomNativeService> { public: virtual status_t onTransact(uint32_t code ,const Parcel &data,Parcel *reply,uint32_t flag=0); }; #endifICustomNativeService.cpp代码:#include"ICustomNativeService.h"#include<utils/Log.h>#define LOG_TAG "ICustomNativeService"using namespace android;enum{ GET_STATE = IBinder::FIRST_CALL_TRANSACTION, NONE};/*实现通信的Bp端*/class BpCustomNativeService : public BpInterface<ICustomNativeService>{ public: BpCustomNativeService(const sp<IBinder> &impl) : BpInterface<ICustomNativeService>(impl) {} int32_t getState() //客户端调用接口 { SLOGD("Bp->getState"); Parcel data , reply; data.writeInterfaceToken(ICustomNativeService::getInterfaceDescriptor()); remote()->transact(GET_STATE,data,&reply); int32_t state = reply.readInt32(); return state; }};IMPLEMENT_META_INTERFACE(CustomNativeService,"native.ICustomNativeService"); //这个是头文件中和声明宏对应的实现宏,注意要放在BpCustomNativeService的实现之后。/*重写onTransact方法,注意类型要完全对应,否者会引起onTransact的调用错误*/status_t BnCustomNativeService::onTransact(uint32_t code,const Parcel &data,Parcel *reply,uint32_t flag){ switch(code) { case GET_STATE : { SLOGD("Bn->getState"); CHECK_INTERFACE(ICustomNativeService,data,reply); int32_t state = (int32_t)getState(); reply->writeInt32(state); return NO_ERROR; } default: { return BBinder::onTransact(code,data,reply,flag); } }}CustomNativeService.cpp代码:#include"ICustomNativeService.h"#include<binder/IServiceManager.h>#include<binder/IPCThreadState.h>#include<utils/Log.h>#define LOG_TAG "CustomNativeService"class CustomNativeService : public BnCustomNativeService{ public : //国际惯例,这两个函数先实现着 CustomNativeService() {} virtual ~CustomNativeService() {} public : int32_t getState() //实现服务接口 { SLOGD("getState"); return 168; }/*android中所有的服务,包括运用层中的服务,都需要向ServiceManager注册,顾名思义,它是管理服务的*/ static void instantiate() { /*通过defaultServiceManager方法得到ServiceManager,然后通过addService注册服务*/ defaultServiceManager()->addService(String16("CustomNativeService"),new CustomNativeService()); }};/*实现main,启动binder通信线程池*/ int main(int argc ,char **argv) { SLOGD("run main"); CustomNativeService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; } Android.mk代码:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := \ common/ICustomNativeService.cpp \ CustomNativeService.cpp \LOCAL_SHARED_LIBRARIES := libutils libbinder libcutilsLOCAL_MODULE_TAGS := optionalLOCAL_MODULE := CustomNativeServiceinclude $(BUILD_EXECUTABLE)这样,执行 mmm external\myservice\CustomNativeService\,就可以得到可执行文件CustomNativeService,在init.rc中添加:service cns /system/bin/CustomNativeService ,在平台启动时CustomNativeService就会跑起来了。下一步来实现一个类,android.myservice.CustomNativeService作为API来调用本地服务的getState方法。分两部分,java部分和JNI部分。java部分: 在framework/base/core/java/android/目录下新建myservice文件夹,在里面新建CustomNativeService.java文件,代码如下:package android.myservice;import android.content.Context;public class CustomNativeService{ Context mContext; public CustomNativeService(Context mContext) { this.mContext = mContext; } native int getState(); public int getServiceState() { return getState(); }}JNI部分: 在framework/base/core/jni/下面新建myservice文件夹,在里面新建CustomNativeServiceJNI.cpp ,代码如下:#define LOG_TAG "CustomNativeServiceJNI"#include<ICustomNativeService.h>#include<binder/IServiceManager.h>#include<utils/RefBase.h>#include<binder/IBinder.h>#include<jni.h>#include<JNIHelp.h>#include<android_runtime/AndroidRuntime.h>#include<utils/Log.h>using namespace android;int getState(){ SLOGD("getstate"); sp<IBinder> iBinder = defaultServiceManager()->getService(String16("CustomNativeService")); if(iBinder != NULL) { sp<ICustomNativeService> service = ICustomNativeService::asInterface(iBinder); return (int)service->getState(); } else { SLOGE("get service failed!"); return 0; }}static JNINativeMethod method_table[] ={ {"getState","()I",(void*)getState},};int register_android_myservice_CustomNativeService(JNIEnv *env){ return AndroidRuntime::registerNativeMethods(env,"android/myservice/CustomNativeService",method_table,NELEM(method_table));}编写JNI要仔细,这段JNI在libandroid_runtime.so中,如果有错误会导致手机开机停留在开机动画界面。在framework/base/core/jni/Android.mk中加入: LOCAL_SRC_FILES:= \ ...... myservice/CustomNativeServiceJNI.cpp \ ../../../../external/myservice/CustomNativeService/common/ICustomNativeService.cpp \LOCAL_C_INCLUDES += \ ...... external/myservice/CustomNativeService/common \在framework/base/core/jni/AndroidRuntime.cpp中:声明: extern int register_android_myservice_CustomNativeService(JNIEnv *env);在 static const RegJNIRec gRegJNI[] = { 加入: ...... REG_JNI(register_android_myservice_CustomNativeService), ......注意,更新API要执行命令 make update-api,然后再执行 make 即可。在运用层中使用服务时,引包即可:import android.myservice.CustomNativeService; CustomNativeService cns = new CustomNativeService(this); //注意,this是要继承了Context的 cns.getServiceState();