C++层Service的创建与使用
来源:互联网 发布:卫计委大数据 编辑:程序博客网 时间:2024/05/21 10:10
Android的service可以分为c++层面的和Java层面的。这是一个例子,介绍了如何在c++层面创建service,并且如何在java应用程序中使用这个service. 这个例子很简单,c++层的service就是提供了一个相加和一个相减的功能。java应用里面就是添加了几个控件来调用c++ service的加减功能实现两个数的相加和相减,并且显示出来。
首先来看看c++层的service是如何创建的。先创建一个ICalcService.h的文件,里面定义了一个接口,包含了一个相加的sum函数接口和一个相减的minus的函数接口。
#ifndef _ICALC_SERVICE_H#define _ICALC_SERVICE_H#include <binder/IInterface.h>#include <binder/IPCThreadState.h>#include <binder/ProcessState.h>#include <binder/IServiceManager.h>#include <cutils/properties.h>#include <utils/Log.h>namespace android { /**********************************************/ /*! @class ICalcService @brief Calc Service Proxy Interface class ***********************************************/ class ICalcService : public IInterface { public: DECLARE_META_INTERFACE(CalcService); virtual int32_t sum(int32_t x, int32_t y) = 0; virtual int32_t minus(int32_t x, int32_t y) = 0; protected: enum{ CALC_SUM = IBinder::FIRST_CALL_TRANSACTION, CALC_MINUS }; };}#endif
再定义一个CalcService.h的头文件
#ifndef _CALC_SERVICE_H#define _CALC_SERVICE_H#include <utils/Log.h>#include "ICalcService.h"namespace android { /**********************************************/ /*! @class ICalcService @brief Calc Service Proxy Interface class ***********************************************/ class BnCalcService : public BnInterface<ICalcService> { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); }; class CalcService : public BnCalcService { public: CalcService(); ~CalcService(); virtual int32_t sum(int32_t x, int32_t y); virtual int32_t minus(int32_t x, int32_t y); static void instantiate(); };}#endif
再定义一个CalcService.cpp的实现文件
#define TAG "CalcService"#include "CalcService.h"#include <utils/Log.h>namespace android {class BpCalcService : public BpInterface<ICalcService> { public: BpCalcService(const sp<IBinder>& impl) : BpInterface<ICalcService>(impl) { } virtual int32_t sum(int32_t x, int32_t y) { LOGD("BpCalcService sum."); Parcel data, reply; data.writeInterfaceToken(ICalcService::getInterfaceDescriptor()); data.writeInt32(x); data.writeInt32(y); remote()->transact(CALC_SUM,data,&reply); int32_t sumxy = reply.readInt32(); LOGD("sumxy=%d",sumxy); return sumxy; } virtual int32_t minus(int32_t x, int32_t y) { LOGD("BpCalcService sum."); Parcel data, reply; data.writeInterfaceToken(ICalcService::getInterfaceDescriptor()); data.writeInt32(x); data.writeInt32(y); remote()->transact(CALC_MINUS,data,&reply); int32_t mxy = reply.readInt32(); LOGD("minuxsy=%d",mxy); return mxy; } };IMPLEMENT_META_INTERFACE(CalcService,"com.test.ICalcService");status_t BnCalcService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ LOGD("onTransact received request."); reply->writeInt32(0); switch(code) { case CALC_SUM: { LOGD("calc sum"); CHECK_INTERFACE(ICalcService,data,reply); int32_t x = data.readInt32(); int32_t y = data.readInt32(); int32_t sumxy = sum(x,y); reply->writeInt32(sumxy); return NO_ERROR; } case CALC_MINUS: { LOGD("calc minus"); CHECK_INTERFACE(ICalcService,data,reply); int32_t x = data.readInt32(); int32_t y = data.readInt32(); int32_t minusxy = minus(x,y); reply->writeInt32(minusxy); return NO_ERROR; } default:{ return BBinder::onTransact(code,data,reply,flags); } }}CalcService::CalcService(){ LOGD("constructor of CalcService");}CalcService::~CalcService(){ LOGD("destructor of CalcService");}int32_t CalcService::sum(int32_t x, int32_t y){ return (x+y);}int32_t CalcService::minus(int32_t x, int32_t y){ return (x-y);}void CalcService::instantiate(){ LOGD("CalcService instantiate."); LOGD("CalcService:ServiceManager: start\n"); defaultServiceManager()->addService(String16("calcservice"),new android::CalcService());}}
从上面可以看见CalcService从BnCalcService继承而来,而BnCalcService从BnInterface继承而来,我们还能看见一个BpCalcService的类,他继承于BpInterface。实际上BnCalcService也就是CalcService是service功能的本地实现,是真正做事情的地方,它是单独的一个进程。而BpCalcService是service的一个代理,对使用这个service的应用而言,应用只与BpService也就是代理打交道。应用并不与BnCalcService往来。在BpCalcService的函数内都使用了remote()->transact,这实际上是通过IPC与BnCalcService通信,BnCalcService的onTransact响应。
instantiate函数内通过defaultServiceManager向service manager注册这个service,其名字就是calcservice,那么应用就可以使用这个名字获取这个service.
另外还需要创建一个可执行程序通过init.rc来运行这个service. 创建一个叫Calc.cpp的文件
#include "ICalcService.h"#include "CalcService.h"using namespace android;int main(int argc, char **argv){ sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); LOGD("CalcService: %p",sm.get()); android::CalcService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
然后要添加Android.mk文件编译
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)ifeq ($(TARGET_BUILD_TYPE),debug)LOCAL_CFLAGS += -DDEBUGendifLOCAL_PRELINK_MODULE := false#Binder ProxyLOCAL_MODULE := libCalcServiceLOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := CalcService.cpp LOCAL_SHARED_LIBRARIES := libbinder libutilsinclude $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)# calcLOCAL_MODULE := calcLOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := Calc.cpp LOCAL_PRELINK_MODULE := falseLOCAL_SHARED_LIBRARIES := libbinder libutils libCalcServiceinclude $(BUILD_EXECUTABLE)
CalcService.cpp生成的是一个库libCalcService,Calc.cpp生成的是一个可执行文件。最后添加这两行到init.rc启动这个服务
service calcservice /system/bin/calc class services
通过以上的代码我们已经在c++层面创建了一个service,并且系统启动后这个service 就运行起来了。那么如何在java应用程序中使用这个service呢?
下面就通过一个例子来说说,创建一个CalcServiceTest的android工程,修改main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ><LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dip" > <EditText android:id="@+id/sxText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/><TextView android:layout_width="20dip" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:text="@string/sum" /><EditText android:id="@+id/syText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/><Button android:id="@+id/sumBtn" android:layout_width="100dip" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:text="@string/equal"/><EditText android:id="@+id/sumText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/> </LinearLayout><LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dip" > <EditText android:id="@+id/mxText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/><TextView android:layout_width="20dip" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:text="@string/minus" /><EditText android:id="@+id/myText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/><Button android:id="@+id/minusBtn" android:layout_width="100dip" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:text="@string/equal"/><EditText android:id="@+id/minusText" android:layout_width="200dip" android:layout_height="wrap_content" android:numeric="integer"/> </LinearLayout> </LinearLayout>
这个xml定义了一个layout,第一行控件是用来输入x,y两个计算数,点击等号的控件后,把相加的结果显示出来;第二行的控件是计算相减并且显示出来。
然后strings.xml
<?xml version="1.0" encoding="utf-8"?><resources> <string name="hello">Hello World, CalcServiceTest!</string> <string name="app_name">CalcServiceTest</string> <string name="sum">+</string> <string name="minus">-</string> <string name="equal">=</string></resources>
定义一个叫ICalcService.aidl的文件,这个文件很重要,通过它才能与service通信,这个接口有两个函数,对应了CalcService内的两个函数
package com.test;interface ICalcService{ int sum(int x, int y); int minus(int x, int y);}
如果是eclipse会自动生成一个叫ICalcService.java的文件,其中你可以见这么行代码
private static final java.lang.String DESCRIPTOR = "com.test.ICalcService"
注意CalcService.cpp内的
IMPLEMENT_META_INTERFACE(CalcService,"com.test.ICalcService");两者的名字必须一致,否则无法实现正常的通信。
修改CalcServiceTest.java
package com.test;import android.app.Activity;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.os.ServiceManager;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import com.test.ICalcService;public class CalcServiceTest extends Activity { /** Called when the activity is first created. */private EditText et1,et2,et3;private Button sumBtn, minusBtn;private String TAG = "CalcServiceTest";private ICalcService mService; @Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG,"onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.main); getCalcService(); ((Button)findViewById(R.id.sumBtn)).setOnClickListener(listener); ((Button)findViewById(R.id.minusBtn)).setOnClickListener(listener); } private void getCalcService() { IBinder calcServiceBinder; Log.d(TAG,"getCalcService"); calcServiceBinder = (IBinder)ServiceManager.getService("calcservice"); if(calcServiceBinder != null) mService = ICalcService.Stub.asInterface(calcServiceBinder); else Log.d(TAG,"calcServiceBinder is null."); } private OnClickListener listener = new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubint x,y,z=0;switch(v.getId()){case R.id.sumBtn:{et1 = (EditText)findViewById(R.id.sxText);et2 = (EditText)findViewById(R.id.syText);et3 = (EditText)findViewById(R.id.sumText);x = Integer.parseInt(et1.getText().toString());y = Integer.parseInt(et2.getText().toString());//z = x + y;if(mService != null){try{z = mService.sum(x,y);Log.d(TAG,"sum="+String.valueOf(z));}catch(RemoteException e){e.printStackTrace();}}else{Log.d(TAG,"mService is null.");}et3.setText(String.valueOf(z));break;}case R.id.minusBtn:{et1 = (EditText)findViewById(R.id.mxText);et2 = (EditText)findViewById(R.id.myText);et3 = (EditText)findViewById(R.id.minusText);x = Integer.parseInt(et1.getText().toString());y = Integer.parseInt(et2.getText().toString());//z = x - y;if(mService != null){try{z = mService.minus(x, y);Log.d(TAG,"minus="+String.valueOf(z));}catch(RemoteException e){e.printStackTrace();}}else{Log.d(TAG,"mService is null.");}et3.setText(String.valueOf(z));break;}default:Log.d(TAG, "No mapping id.");}} };}
仔细看getCalcService函数,其表明了如何将c++层的服务获取并且转换为java可以识别的aidl接口。通过转换后就可以简便地调用了。在listener中就调用了calcservice的sum和minus功能实现加减。创建Android.mk编译这个apkLOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_PACKAGE_NAME := CalcServiceTestLOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under,src)LOCAL_STATIC_JAVA_LIBRARIES :=LOCAL_JAVA_LIBRARIES :=LOCAL_PROGUARD_FLAG_FILES := proguard.flagsinclude $(BUILD_PACKAGE)include $(call all-makefiles-under, $(LOCAL_PATH))
在CalcServiceTest.apk生成后通过app luancher就可以运行这个apk,通过logcat或者实际运行效果,我们可以看见apk与c++ service实现了正常的通信。
- C++层Service的创建与使用
- Service 服务的创建与使用
- Android -- service 服务的创建与使用,生命周期,电话监控器
- Dao与Service层的设计
- service与dao层的不同点
- (C#)Windows Forms Service 创建,使用,跟踪
- 如何在Service层创建虚拟的根节点
- [C#] 创建一个简单的Windows Service
- DAO与Service层的泛型抽取与实现
- 【基于SSH框架的个人博客系统04】DAO层,Service层与Action层
- service层的作用
- service层的封装
- service层的意义
- DAO层与Service层区别?
- S2SH合并DAO层与service层
- oracle service 的创建、使用-基础分析
- 使用MVC模式实现用户转账功能(区分dao层与service层)
- Service的概念与使用
- EXTJS 2.2版本在IE9中会报错:对象不支持“createContextualFragment”属性或方法
- About 异步编程
- 安装iis5.1时找不到zClientm.exe的解决方法
- Web数据挖掘综述
- ubuntu下vim的配置和改造
- C++层Service的创建与使用
- MFC属性页和向导对话框的创建
- On Story Estimation: 单一职责原则
- Mybatis学习笔记一(环境搭建)
- 研发 vs 售前
- java文件和目录操作类代码
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- 回头时,不后悔
- Sicily 1001. Alphacode