参考实作:http://blog.csdn.net/belyxiong/article/details/5875993 为android添加底层核心服务
参考博文中信息不全且有小小问题,本文对整个过程稍作整理并对内容作了补全和修正。
user@ubuntu:/$ sudo adb shell
root@android:/ # cd system/lib --> 服务的库文件
root@android:/ # cd system/bin --> 服务的可执行文件
root@android:/ # cat init.rc --> 服务的配置文件
服务启动过程:
在init.rc里添加service,这样就会调用服务的可执行文件,将服务加到ServiceManager中,这样,应用就可以获取服务方法。
下面ubuntu当前目录为:整个android4.0工程根目录,包含frameworks,system,packages等子目录。
1、自定义服务MyService库
$ mkdir -p frameworks/base/MyService/libmyservice
$ cd frameworks/base/MyService/libmyservice
$ touch Android.mk MyService.h MyService.cpp
Android.mk内容:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= MyService.cpp
LOCAL_MODULE := libMyService
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libandroid_runtime
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY) #这一行表示编译为动态库
注意: LOCAL_MODULE_TAGS那一行要写在两个include $中间
MyService.h内容:
#ifndef ANDROID_GUILH_MY_SERVICE_H
#define ANDROID_GUILH_MY_SERVICE_H
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/threads.h>
namespace android {
class MyService : public BBinder{// 从 BBinder 派生,实现本地接口
public:
static int instantiate();
MyService();
virtual ~MyService();
virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
};
}; //namespace
#endif
MyService.cpp内容:
#include "MyService.h"
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
namespace android {
static struct sigaction oldact;
static pthread_key_t sigbuskey;
// 把自己注册到系统中
int MyService::instantiate() {
LOGE("MyService::instantiate");
// 这里主要是把
//MySerice 这个服务添加到 Binder Driver 中服务名为 guilh.MyService
int r = defaultServiceManager()->addService(
String16("guilh.MyService"), new MyService());
LOGE("MyService r = %d/n", r);
return r;
}
// 构造函数
MyService::MyService()
{
LOGE("MyService created");
pthread_key_create(&sigbuskey, NULL);
}
// 析构函数
MyService::~MyService()
{
pthread_key_delete(sigbuskey);
LOGE("MyService destroyed");
}
// 这个是服务具体的本地实现,功能实现都应该放在这里面,通过传入执行代码( code )
// 的不同来执行不同的操作,上层隐射为不同的 api 。
status_t MyService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
LOGE("MyService::onTrascat");
switch(code) {
// 只处理 code == 0 的情况 case 0:
{// 读取data中的整数,并对它做加1000的操作,然后将结果写到reply中
pid_t pid = data.readInt32();
int num = data.readInt32();
num = num + 1000;
reply->writeInt32(num);
return NO_ERROR;
}
break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; //namespace
然后用mmm编译生成libMyService.so,
$ adb push out/target/product/xxx/system/lib/libMyService.so /system/lib/
根据工程替换上方的xxx。
2、自定义服务MyService可执行文件,myserver
$ mkdir -p frameworks/base/MyService/myserver
$ cd frameworks/base/MyService/myserver
$ touch Android.mk MyServer.cpp
Android.mk内容:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= MyServer.cpp
LOCAL_SHARED_LIBRARIES := \
libMyService \
libutils \
libbinder
LOCAL_MODULE:= myserver
LOCAL_MODULE_TAGS:= optional
include $(BUILD_EXECUTABLE) #编译为可执行文件
MyServer.cpp内容:
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
#include "../libmyservice/MyService.h"
using namespace android;
int main(int argc, char** argv)
{
LOGE("MyServer::main");
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();//取得 ServiceManager
LOGE("ServiceManager: %p", sm.get());
MyService::instantiate();//把自己添加到 ServiceManager中
ProcessState::self()->startThreadPool();//启动缓冲池
IPCThreadState::self()->joinThreadPool();//这里是把服务添加到 Binder闭合循环进程中
}
然后用mmm编译生成myserver,
$ adb push out/target/product/xxx/system/bin/myserver /system/bin/
3、修改init.rc
$ cd system/core/rootdir
编辑 init.rc,在末尾加上:
# MyService
service myserver /system/bin/myserver
class main
user root
$ make bootimage
$ sudo adb reboot bootloader
$ sudo fastboot flash boot out/target/product/xxx/boot.img
$ sudo fastboot reboot
4、运行MyService测试程序
$ cd packages/apps/
$ android list
根据结果将下面命令的id替换成合适的值。
$ android create project --target id --name MyServiceTest --path MyServiceTest --activity MyServiceTestActivity --package com.example.myapp
$ cd MyServiceTest
$ vi Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MyServiceTest
LOCAL_CERTIFICATE := platform
#LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_FLAGS := -include $(LOCAL_PATH)/proguard.flags
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
$ vi res/layout/main.xml
删掉<TextView>中的 android:text那行,否则会因为语言编译不通过。
或者在 Android.mk 中加上 tests: LOCAL_MODULE_TAGS := optional tests
$ vi src/com/example/myapp/MyServiceTestActivity.java
package com.example.myapp;
import android.app.Activity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.ServiceManager;
import android.os.Process;
import android.util.Log;
public class MyServiceTestActivity extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("MyService","MyService::onCreate");
setContentView(R.layout.main);
test();
}
private void test(){
try{
Log.d("Myservie","MyService::test");
IBinder binder = ServiceManager.getService("guilh.MyService");// 取得服务
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
if(binder == null)
Log.d("MyService","failed to get service");
data.writeInt(Process.myPid());// 固定操作
data.writeInt(100);// 传入参数
binder.transact(0, data, reply, 0);// 执行远程调用
Log.d("MyService","result="+reply.readInt());// 验证结果
}catch(Exception e){
Log.d("MyService",e.toString());
}
}
}
然后用mmm编译生成MyServiceTest,
$ adb install -r out/target/product/xxx/system/app/MyServiceTest.apk
最后,在手机上运行MyServiceTest程序,
通过 logcat -s MyService 查看log,可以发现服务运行,测试成功获取服务。