众所周知,Android的服务分Native Service和Android Service两种,为什么一上来就整Native Service呢,原因很简单,因为C++比较上手啊,才怪,是因为老大让我做个Service与应用的调研啦。
接下来就是菜鸟的基本路线,在拿到Android的工程后,了解基本编译指令后,就开始在网上搜索,于是找到博文为Android添加底层核心服务,然后依葫芦画瓢,在framework/base目录下添加自己的工作目录xService,并在里面分别建立两个目录,一个是libxService,用于实现xService类,一个是xServer,用于添加服务到Service Manager中。
我这里只展示下主要代码,xService类instantiate:
int xService::instantiate()
{
sp<IBinder> binder;
sp<IServiceManager> sm = defaultServiceManager();
ALOGD("[xiao] xService instantiate with %p", sm.get());
// 这里主要把xService这个服务添加到Binder Driver中,服务名为guilh.x
int r = sm->addService(String16("xService"), new xService());
ALOGD("[xiao] xService result=%d", r);
return r;
}
这里需要注意的是日志的输出,原文中的LOGE、LOGV之类是一概编译不过的,事实上Native层的输出可以使用cutils/log.h中的ALOG系列,即在前加个A。
然后就是响应调用:
status_t xService::onTransact(uint32_t code, const Parcel& data, Parcel *reply, uint32_t flags)
{
ALOGD("[xiao] onTrasact()->enter with code: %d", code);
switch (code) // 根据code的不同执行不同的操作
{
case 0:
{
pid_t pid = data.readInt32();
int num = data.readInt32();
if (8 == num)
{
reply->writeInt32(8);
reply->writeString8(String8("hello world by String8!"));
}
else if (16 == num)
{
reply->writeInt32(16);
reply->writeString16(String16("hello world by String16!"));
}
else
{
reply->writeInt32(num+1000);
}
return NO_ERROR;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
因为应用层的Parcel类只有readString方法,所以这里我做了个分支确认下实际对应的Native层是哪种String,事实上在我测试中显示是String16类型的。
另需要注意的有两点:
1、在写添加服务到Service Manager的应用时,需添加下面这一句,以便让应用生成到system/bin目录下,否则会生成到symbol/system/bin,那么在init.rc中添加因无法找到应用,无法自启动服务。
LOCAL_MODULE_TAGS := eng
2、如何修改init.rc的问题,如果只是remake工程,可直接修改生成的中间文件mediatek/config/out/[pName]/init.rc或out/target/product/[pName]/root/init.rc,其中[pName]为
实际工程名称,但这种修改会在new后还原,如需在根本上修改,在我这边使用的MTK项目中,则需修改mediatek/config/mt6572/init.rc,不过这个需new才会生效。在init.rc的末尾添加以下这一句:
service xService /system/bin/xServer
class main
至于在应用中调用服务接口,如按原文做法:
IBinder binder = ServiceManager.getService("xService");// 取得服务
则只能做为内置应用,如想用像普通应用那样在Eclipse中开发调试,刚需可采用以下方法获取服务:
private IBinder getBinderObj(){
IBinder binder = null;
try{
Method m = Class.forName("android.os.ServiceManager").getMethod("getService", new Class[]{String.class});
if(m != null){
Log.d(TAG, "getBinderObj Method:"+m.toString());
}else{
Log.d(TAG, "getBinderObj Method null");
}
binder = (IBinder)m.invoke(null, new Object[]{"xService"});
if(binder != null){
Log.d(TAG, "getBinderObj binder:"+binder.toString());
}else{
Log.d(TAG, "getBinderObj binder null");
}
}catch(Exception e){
Log.d(TAG, "getBinderObj exception:"+e.toString());
}
return binder;
}
这样即可很方便的测试服务。