编写第一个Android Native Service

编写第一个Android Native Service :SQRService,求平方(Square)运算。


为什么有核心服务呢? 
1. 核心服务是 Android 框架里最接近Linux/Driver 的部分。为了充分发挥硬件设备的差异化特性,核心服务是让上层Java 应用程序来使用Driver/HW Device 特色的重要管道。
2. 在开机过程中,就可以启动核心服务(例如汉字输入法服务等),让众多应用程序来共享之。
3. 由于共享,所以能有效降低 Java 应用程序的大小(Size)。


看图!

编写第一个Android Native Service_第1张图片


步骤:

I、编写Native Service:SQRService

II、编写SQR.cpp来使用SQRService

III、编写Java层Client来使用核心服务

IV、编写一个Java层Activity


分析:
1、核心服务通常在特定的进程(Process)里执行。
2、必须提供IBinder接口,让应用程序可以进行跨进程的绑定(Binding)和调用。
3、因为共享,所以必须确保多线程安全(Thread-safe)。
4、以C++类定义,诞生其对象,通过SM的协助,将该对象参数传给IServiceManager::addService函数,就加入到Binder Driver里了。
5、应用程序可以通过SM的协助远距离绑定该核心服务,此时SM会回传IBinder接口给应用程序。
6、应用程序可通过IBinder::transact()函数来与核心服务互传资料。


I、

以C++编写一个SQRService,它的功能是将一个数值(例如5)做平方的运算,然后传出其计算结果(5^2 = 5*5 = 25)。


SQRService.h

//SQRService.h
namespace android{
class SQRService:public BBinder{
	public:
	static int instantiate();
	virtual status_t onTransact(uint32_t,const Parcel&,Parcel*,uint32_t);
	SQRService();
	virtual ~SQRService();
}
 注意:在Java层,Binder类实现了IBinder接口; 
  

在C++层,BBInder类实现了IBinder接口。

SQRService.cpp

//SQRService.cpp
namespace android{
	enum{
		SQUARE = IBinder::FIRST_CALL_TRANSACTION,
	};
	int SQRService::instantiate(){
		LOGE("SQRService instantiate");
		int r = defaultServiceManager()->addService(String16("com.devwang.sqr"),new SQRService());
		LOGE("SQRService r = %d \n",r);
		return r;
	}
	SQRService::SQRService(){
		LOGV("SQRService created");
	}
	SQRService::~SQRService(){
		LOGV("SQRService destroyed");
	}
	status_t SQRService::onTransact(uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags){
		switch(code){
			case SQUARE:{
				int num = data.readInt32();
				reply->writeInt32(num*num);//平方运算
				LOGE("onTransact::CREATE_NUM.. num = %d \n",num);
				return NO_ERROR;
			}
			break;
			default:
			LOGE("onTransact::default\n");
                        return BBinder::onTransact(code,data,reply,flags);
		}
        }
}//namespace android
 
  
 
  

编写一个Make文件:

Android.mk

//Android.mk 
LOCAL_MODULE:=libSQRS

执行此Android.mk就可进行编译(Cpmpile)和链接(Link),生成libSQRS.so共享库。



使用C++编写可独立执行的sqrserver.cpp程序。此程序先创建SQRService的对象,然后将它添加到Binder Driver里。 

注意:
暂时不改写init.rc文件,以及重新启动设备(以防服务有错导致死机);
先使用sqrserver程序来测试这个核心服务。


此sqrserver.cpp的内容如下:
sqrserver.cpp
//sqrserver.cpp
using namespace android;
int main(int argc, char const *argv[])
{
	sp proc(ProcessState::self);
	sp sm = defaultServiceManager();
	LOGI("ServiceManager:%p",sm.get());
	SQRService::instantiate();
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
	return 0;
}




上述步骤,分别建立了libSQRS.so和sqrserver可执行程序。
然后将libSQRS.so放入Android仿真器的/system/lib里。并且,将sqrserver程序放入Android仿真器的/sysytem/bin里。
执行sqrserver程序,就将SQRService对象加入Binder Driver里。


注意:
先不要杀掉sqrserver进程


II、
编写SQR.cpp来使用SQRService
编写一个本地层Client
以C++编写一个SQR.cpp的C++层应用程序,它可以通过ServiceManager去绑定(Bind)SQRService.
然后调用IBinder::transact()函数,进而调用SQRService核心服务的onTransact()去进行平方运算的服务。

SQR.h
//SQR.h
namespace android{
	class SQR
	{
	private:
		const void getSQRService();
	public:
		SQR();
		int execute(int n);
	}
}//namespace android



SQR.cpp
//SQR.cpp
namespace android{
	sp m_ib;
	SQR:SQR(){
		getSQRService();
	}
	const void SQR::getSQRService(){
		sp sm = defaultServiceManager();
		m_ib = sm->getService(String16("com.devwang.sqr"));
		LOGE("SQR:getSQRService %p\n",sm.get());
		if(m_ib == 0){
			LOGW("SQRService not published,wating...");
		}
		return;
	}
	SQR::execute(int n){
		Parcel data,reply;
		data.writeInt32(n);
		LOGE("SQR::execute\n");
		m_ib->transact(0,data,&reply);
		int num = reply.readInt32();
		return num;
	}


}


在构造函数SQR()里调用getSQRService来获得服务(亦即绑定服务)。
取得服务时ServiceManager传回BpBinder的IBinder接口。
而execute()函数则实际调用IBinder接口的transact()函数,并转而调用onTransact()函数。

III、
编写Java层Client来使用核心服务
编写一个Java层Client
以Java编写一个sqr.java 


Java层的应用程序可以通过JNI Native Code来调用SQR类别,进而取得SQRService服务。

com_devwang_service_sqr.cpp
//com_devwang_service_sqr.cpp
using namespace ansroid;
JNIEXPORT jint JNICALL Java_com_devwang_service_sqr_execute(JNIEnv *env,jobject thiz,jint x){
	char s[] = "Java_com_devwang_service_sqr_execute!!!";
	LOGE("%s x = %d\n",s,x);
	SQR* sqrObj = new SQR();
	int num = sqrObj->execute(x);
	return num;
}


执行Android.mk文件,生成libSQRS_jni.so共享库,就可以加载手机或模拟器里执行了。
执行时,Native函数调用SQR,转而调用BpBinder。


设计Java层的应用类别来调用上述的JNI Native Code,就完成串接Java应用程序与硬件驱动的目的了。
于是,编写一个与JNI Native Code相对应的Java类别。

sqr.java
//sqr.java
package com.devwang.service;
public class sqr{
	static{
		system.loadLibrary("libSQRS_jni");
	}
	public static native int execute(int x);
};



当此sqr类别被加载到内存时,就会把libSQRS_jni.so也加载进来,于是sqr类别就与libSQRS_jni.so结合起来了;而且sqr.execute()函数就能调用到libSQRS_jni.so里的JNI Natice函数了。


IV、

编写一个Java层Activity,如:sqrActivity.java,使用sqr.java中的native函数即OK。


视频教程:参照以下这三个,不得不说高老的视频很赞,得有强硬的基础才能看懂。

编写第一个Android Native Service_第2张图片


你可能感兴趣的:(linux,android,c++,java)