C++层Service的创建与使用

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 += -DDEBUG
endif

LOCAL_PRELINK_MODULE := false

#Binder Proxy
LOCAL_MODULE := libCalcService
LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := CalcService.cpp 

LOCAL_SHARED_LIBRARIES := libbinder libutils

include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)

# calc
LOCAL_MODULE := calc
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := Calc.cpp 

LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES := libbinder libutils libCalcService


include $(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()
    {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			int 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编译这个apk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_PACKAGE_NAME := CalcServiceTest

LOCAL_MODULE_TAGS := optional

LOCAL_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.flags

include $(BUILD_PACKAGE)

include $(call all-makefiles-under, $(LOCAL_PATH))

在CalcServiceTest.apk生成后通过app luancher就可以运行这个apk,通过logcat或者实际运行效果,我们可以看见apk与c++ service实现了正常的通信。




  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值