【Android Native Code开发系列】六 一个Native Service的完整示例

/*
* blackboy   [email protected]
* QQ群: 135202158
* 转载请注明作者及出处
*/


关于Android Native Service的简介及一些例子, 还可以参考longfeey的大作: http://blog.csdn.net/longfeey/article/details/5887026



1. 准备工作

(1)因为要调用Android源代码的framework/base里的一些类,所以要确保有android相关源代码

(2)需要交叉编译器, 链接器等工具, 这个可以使用anroid源码里提供的工具,也可以使用单独下载的android ndk

(3)可选: 如果在模拟器(AVD)上运行和调试, 还需要有编译好或者单独下载的android sdk及相应的组件等等, 关于各种组件需求,见

http://developer.android.com/sdk/installing.html#components提到的"Recommended Components", 确保满足"Basic"需求 

这里用的环境是android源码+单独下载的SDK(包括sdk toos, sdk platform tools和platform组件)


2. 在android源码主目录/development子目录下建立工程目录, 我们的各个模块的代码都将放在这个目录的子目录下

cd  ~/android/development
mkdir zp_module


3. 建立service目录,里面放要做的native service源码


ZPService.h

#ifndef ANDROID_ZPSERVICE_H
#define ANDROID_ZPSERVICE_H

#include 
#include 
#include 

namespace android
{
	class ZPService : public BBinder
	{
	private:
		//mutable Mutex m_Lock;
		//int32_t m_NextConnId;

	public:
		static int Instance();
		ZPService();
		virtual ~ZPService();
		virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
	};
}

#endif


ZPService.cpp

#include 
#include 
#include "ZPService.h"

namespace android
{
	//static struct sigaction oldact;
	static pthread_key_t sigbuskey;
	
	int ZPService::Instance()
	{
		LOGE("ZPService Instantiate\n");
		int ret = defaultServiceManager()->addService(
				String16("zp.svc"), new ZPService());
		LOGE("ZPService ret = %d\n", ret);
		return ret;
	}

	ZPService::ZPService()
	{
		LOGV("ZPService create\n");
		//m_NextConnId = 1;
		pthread_key_create(&sigbuskey,NULL);
	}

	ZPService::~ZPService()
	{
		pthread_key_delete(sigbuskey);
		LOGV("ZPService destory\n");
	}

	status_t ZPService::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 += 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:=ZPService.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=libZPService
LOCAL_PRELINK_MODULE:=false
include $(BUILD_SHARED_LIBRARY)


4. 建立svcserver目录,放置server源代码, 它主要用来将我们的service注册到系统. 

zpserver.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "../service/ZPService.h"

using namespace android;


int main(int arg, char** argv)
{
	printf("server - ain() begin\n");
	sp proc(ProcessState::self());
	sp sm = defaultServiceManager();
	//LOGI("ServiceManager: %p\n", sm.get());
	printf("server - erviceManager: %p\n", sm.get());
	int ret = ZPService::Instance();
	printf("server - ZPService::Instance return %d\n", ret);
	ProcessState::self()->startThreadPool();

Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=zpserver.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder libZPService
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=zpserver
include $(BUILD_EXECUTABLE)


5.  创建svcclient目录, 放置client源代码,它用于调用service提供的服务. 它编译成一个动态库,供其他可执行程序调用, 也可以直接将它和第6步的调用程序直接编译成一个可执行文件

ZPClient.h

#ifndef ANDROID_ZPCLIENT_H
#define ANDROID_ZPCLIENT_H

namespace android
{
	class ZPClient
	{
	public:
		int setN(int n);
	private:
		static void getZPService();
	};
}

#endif


ZPClient.cpp

#include 
#include 
#include "ZPClient.h"


namespace android
{
	sp binder;
	
	int ZPClient::setN(int n)
	{
		getZPService();
		Parcel data, reply;
		data.writeInt32(getpid());
		data.writeInt32(n);
		
		LOGE("client - binder->transact()\n");
		binder->transact(0, data, &reply);
		int r = reply.readInt32();
		return r;
	}

	void ZPClient::getZPService()
	{
		sp sm = defaultServiceManager();
		binder = sm->getService(String16("zp.svc"));
		LOGE("client - etService: %p\n", sm.get());
		if(binder == 0)
		{
			LOGW("ZPService not published, waiting...");
			return;
		}
	}

}


Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=ZPClient.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=libZPClient
LOCAL_PRELINK_MODULE:=false
include $(BUILD_SHARED_LIBRARY)


6. 创建svctest目录, 在里面开发一个测试程序,调用第5步的client库提供的接口,访问我们的service

test.cpp

#include 
#include "../svcclient/ZPClient.h"

using namespace android;

int main(int argc, char** argv)
{
	ZPClient client;
	int ret = client.setN(2012);
	printf("setN return: %d\n", ret);
	return 0;
}


Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=test.cpp
LOCAL_SHARED_LIBRARIES:=libZPClient
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=svctest
include $(BUILD_EXECUTABLE)


完成以上几步后, 我们的工程的目录结构如下(zp_module的父目录是development):

zp_module/
|-- Android.mk
|-- service
|   |-- Android.mk
|   |-- ZPService.cpp
|   `-- ZPService.h
|-- svcclient
|   |-- Android.mk
|   |-- ZPClient.cpp
|   `-- ZPClient.h
|-- svcserver
|   |-- Android.mk
|   `-- zpserver.cpp
`-- svctest
    |-- Android.mk
    `-- test.cpp



7. 编译所有项目

第一种方法, 进入android源码主目录,运行

source build/envsetup.sh 或 . build/envsetup.sh
然后进入development下你的源代码的各个子目录, 根据信赖性先后依次编译各个项目,比如进入development/zp_module/service, 运行 mm


第二种方法, 在zp_module下创建一个Android.mk文件, 输入以下内容:

include $(call all-subdir-makefiles

然后直接在zp_module目录下运行mm


8. 在模拟器里调试编译好的东西

(1) 打开emulator 

emulator -avd avd4.0.3 -scale 0.6 -partition-size 256

(2) 打开adb, 等avd就绪后(用adb get-state查看状态,为device即准备好), 将编译好的库和可执行程序送入模拟器

zp@zp-desktop:~$ adb remount
remount succeeded
zp@zp-desktop:~$ adb push /home/zp/android/out/target/product/generic/system/lib/libZPService.so /system/lib
210 KB/s (10216 bytes in 0.047s)
zp@zp-desktop:~$ adb push /home/zp/android/out/target/product/generic/system/lib/libZPClient.so /system/lib
122 KB/s (5516 bytes in 0.044s)
zp@zp-desktop:~$ adb push /home/zp/android/out/target/product/generic/system/bin/zpserver /data
124 KB/s (5572 bytes in 0.043s) 
zp@zp-desktop:~$ adb push /home/zp/android/out/target/product/generic/system/bin/svctest /data
121 KB/s (5568 bytes in 0.044s) 


(3) 进入模拟器shell,先后运行zpserver和svctest

zp@zp-desktop:~$ adb shell
# /data/zpserver
server - ain() begin
server - erviceManager: 0xaa88
server - ZPService::Instance return 0
zp@zp-desktop:~$ adb shell
# /data/svctest
setN return: 3012
#



证明一切正确.

你可能感兴趣的:(C/C++/C#,Android)