华清远见讲师 刘洪涛
一、概述
本文 希望通 过 分析台湾的Jollen的mokoid 工程代 码 ,和在s5pc100平台上 实现过 程种遇到的问题,解析Andorid HAL的 开发 方法。
二、 HAL 介绍
现 有HAL架构由Patrick Brady (Google) 在2008 Google I/O演 讲 中提出的,如下 图 。
Android 的HAL是 为 了保 护 一些硬件提供商的知 识产权 而提出的,是 为 了避 开 linux的GPL束 缚 。思路是把控制硬件的 动 作都放到了Android HAL中,而linux driver 仅仅 完成一些 简单 的数据交互作用,甚至把硬件寄存器空 间 直接映射到user space。而Android是基于Aparch的license,因此硬件厂商可以只提供二 进 制代 码 ,所以 说 Android只是一个 开 放的平台,并不是一个 开 源的平台。也许也正是因 为 Android不遵从GPL,所以Greg Kroah-Hartman才在2.6.33内核将Andorid 驱动 从linux中 删 除。GPL和硬件厂商目前 还 是有着无法弥合的裂痕。Android想要把 这 个 问题处 理好也是不容易的。
总结 下来,Android HAL存在的原因主要有:
1. 并不是所有的硬件 设备 都有 标 准的linux kernel的接口
2. KERNEL DRIVER 涉 及到GPL的版 权 。某些 设备 制造商并不原因公 开 硬件 驱动 ,所以才去用HAL方 式 绕过 GPL。
3. 针对 某些硬件,An有一些特殊的需求
三、 HAL 内容
1、HAL 主要的 储 存于以下目 录 :
(注意:HAL在其它目录下 也可以正常编译)
l libhardware_legacy/ - 旧的架构、采取 链 接 库 模 块 的 观 念 进 行
l libhardware/ - 新架构、 调 整 为 HAL stub 的 观 念
l ril/ - Radio Interface Layer
l msm7k QUAL平台相 关
主要 包含以下一些模 块 :Gps、Vibrator、Wifi、Copybit、 Audio、Camera、Lights、Ril、Overlay等。
2、两种 HAL 架构比较
目前 存在两 种 HAL架构,位于libhardware_legacy目 录 下的“旧HAL架构”和位于libhardware目 录 下的“新HAL架构”。两 种 框架如下 图 所示。
图 3.1 旧HAL 架构 图 3.2 新 HAL 架构
libhardware_legacy 是将 *.so 文件当作shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通 过 直接函数 调 用的方式,来操作 驱动 程序。当然, 应 用程序也可以不需要通 过 JNI 的方式 进 行,直接加 载 *.so (dlopen)的做法 调 用*.so 里的符号(symbol)也是一 种 方式。 总 而言之是没有 经过 封装,上 层 可以直接操作硬件。
现 在的libhardware 架构,就有stub的味道了。HAL stub 是一 种 代理人(proxy)的概念,stub 虽 然仍是以 *.so 檔 的形式存在,但HAL已 经 将 *.so 档 隐 藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则 是向 HAL 取得特定模 块 (stub)的 operations,再 callback 这 些操作函数。 这种 以 indirect function call 的架构, 让 HAL stub 变 成是一 种 包含 关 系,即 HAL 里包含了 许许 多多的 stub(代理人)。Runtime 只要 说 明 类 型,即 module ID,就可以取得操作函数。 对 于目前的HAL,可以 认为 Android定 义 了HAL 层结 构 框架,通 过 几个接口 访问 硬件从而 统 一了 调 用方式。
下面 结 合 实 例来分析HAL 编 程方法。
四、 mokoid 工程代码下载与结构分析
1、mokid项目概述
modkoid 工程提供了一个LedTest示例程序,是台湾的Jollen用于培 训 的。对于理解android层次结构、Hal编程方法都非常有意义。
2、下载方法
#svn checkout http://mokoid.googlecode.com/svn/trunk/mokoid-read-only
3、结构分析
|-- Android.mk
|-- apps //两种应用测试方法
| |-- Android.mk
| |-- LedClient //直接调用service来调用jni
| | |-- AndroidManifest.xml
| | |-- Android.mk
| | `-- src
| | `-- com
| | `-- mokoid
| | `-- LedClient
| | `-- LedClient.java // 第1种方式应用程序实现代码
| `-- LedTest //通过manager来调用jni
| |-- AndroidManifest.xml
| |-- Android.mk
| `-- src
| `-- com
| `-- mokoid
| `-- LedTest
| |-- LedSystemServer.java //开启了一个后台service,下文会有解释
| `-- LedTest.java //第2种方式应用程序实现代码
|-- dma6410xp //这个目录可以 不要
| |-- AndroidBoard.mk
| |-- AndroidProducts.mk
| |-- BoardConfig.mk
| |-- dma6410xp.mk
| |-- init.dma6410xp.rc
| |-- init.goldfish.sh
| `-- init.rc
|-- frameworks //框架代 码
| |-- Android.mk
| `-- base
| |-- Android.mk
| |-- core
| | `-- java
| | `-- mokoid
| | `-- hardware
| | |-- ILedService.aidl
| | `-- LedManager.java //实现了Manager,给第2种方 法用
| `-- service
| |-- Android.mk
| |-- com.mokoid.server.xml
| |-- java
| | `-- com
| | `-- mokoid
| | `-- server
| | `-- LedService.java //Framework service代码
| `-- jni
| |-- Android.mk
| `-- com_mokoid_server_LedService.cpp //jni 代码
|-- hardware
| |-- Android.mk
| |-- libled
| | |-- Android.mk
| | `-- libled.c
| `-- modules
| |-- Android.mk
| |-- include
| | `-- mokoid
| | `-- led.h
| `-- led
| |-- Android.mk
| `-- led.c //led stub 硬件控制代码
`-- README.txt
Android 的 HAL 的 实现 需要通 过 JNI(Java Native Interface) ,JNI 简单 来 说 就是 java 程序可以 调 用 C/C++ 写的 动态链 接 库 , 这样 的 话 ,HAL 可以使用 C/C++ 语 言 编 写 , 效率更高。在Android下 访问 HAL大致有以下两 种 方式:
(1)Android的app可以直接通过service 调 用.so格式的jni
(2) 经过 Manager调用service
上面两种方法应该说是各有优缺点,第一种方法简单高效,但不正规。第二种方法实现起来比较复杂,但更符合目前的Android框架。第二种方法中 ,LegManager 和 LedService (java ) 在两个进程中,需要通过进程通讯的方式来通讯。
mokoid工程中 实现 了上述两 种 方法。下面将 详细 介 绍这 两 种 方法的 实现 原理。
4、第一种方法:直接调用service方法的实现过程
下面 分析第一种方法中,各层的关键代码。
( 1 ) HAL 层
一般 来说HAL moudle需要涉及的是三个关键结构体:
struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;
下面结合代码说 明这 3 个结构的用法。部分代码经过修改 , 后面的章节会给出修改的原因。
文件:mokoid-read-only/hardware/modules/include/mokoid/led.h
- struct led_module_t {
- struct hw_module_t common;
- };
- //HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
- struct led_control_device_t {
- //自定义的一个针对Led控制的结构,包含hw_device_t和支 持的API操作
- struct hw_device_t common;
- /* attributes */
- int fd; //可用于具体的设备描述符
- /* supporting control APIs go here */
- int (*set_on)( struct led_control_device_t *dev, int32_t led);
- int (*set_off)( struct led_control_device_t *dev, int32_t led);
- };
- #define LED_HARDWARE_MODULE_ID "led"
- //定义一个MODULE_ID,HAL层可以根据这个ID找到我 们这个HAL stub
文件 :mokoid-read-only/hardware/modules/led/led.c
- #define LOG_TAG "MokoidLedStub"
- #include <hardware/hardware.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <cutils/log.h>
- #include <cutils/atomic.h>
- //#include <mokoid/led.h>
- #include "../include/mokoid/led.h"
- /*****************************************************************************/
- int fd; //硬件led的设备描述符 。你也可以用led_control_device_t结构中定义的fd
- #define GPG3DAT2_ON 0x4800 //ioctl 控制命令
- #define GPG3DAT2_OFF 0x4801
- int led_device_close( struct hw_device_t* device)
- {
- struct led_control_device_t* ctx = ( struct led_control_device_t*)device;
- if (ctx) {
- free(ctx);
- }
- close(fd);
- return 0;
- }
- int led_on( struct led_control_device_t *dev, int32_t led)
- {
- LOGI("LED Stub: set %d on." , led);
- ioctl(fd,GPG3DAT2_ON,NULL); //控制Led亮灭,和硬件相关
- return 0;
- }
- int led_off( struct led_control_device_t *dev, int32_t led)
- {
- LOGI("LED Stub: set %d off." , led);
- return 0;
- }
- static int led_device_open( const struct hw_module_t* module, const char * name,
- struct hw_device_t** device)
- {
- struct led_control_device_t *dev;
- dev = (struct led_control_device_t *)malloc( sizeof (*dev));
- memset(dev, 0, sizeof (*dev));
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = module;
- dev->common.close = led_device_close;
- dev->set_on = led_on; //实例化支持的操作
- dev->set_off = led_off;
- *device = &dev->common; //将实例化后的led_control_device_t地址返回给jni层
- //这样jni层就可以直接调 用led_on、led_off、led_device_close方法了。
- if ((fd=open( "/dev/led" ,O_RDWR))==-1) //打开硬件设备
- {
- LOGE("LED open error" );
- }
- else
- LOGI("open ok" );
- success:
- return 0;
- }
- static struct hw_module_methods_t led_module_methods = {
- open: led_device_open
- };
- const struct led_module_t HAL_MODULE_INFO_SYM = {
- //定义这个对象等于向系统注册了一个ID为 LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: LED_HARDWARE_MODULE_ID,
- name: "Sample LED Stub" ,
- author: "The Mokoid Open Source Project" ,
- methods: &led_module_methods, //实现了一个open的方法供jni层调用,
- //从而实例化led_control_device_t
- }
- /* supporting APIs go here */
- };
( 2 ) JNI 层
文 件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp
- struct led_control_device_t *sLedDevice = NULL;
- static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)
- {
- LOGI("LedService JNI: mokoid_setOn() is invoked." );
- if (sLedDevice == NULL) {
- LOGI("LedService JNI: sLedDevice was not fetched correctly." );
- return -1;
- } else {
- return sLedDevice->set_on(sLedDevice, led); //调用hal层的注册的方法
- }
- }
- static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led)
- {
- LOGI("LedService JNI: mokoid_setOff() is invoked." );
- if (sLedDevice == NULL) {
- LOGI("LedService JNI: sLedDevice was not fetched correctly." );
- return -1;
- } else {
- return sLedDevice->set_off(sLedDevice, led); //调用hal层的注册的方法
- }
- }
- /** helper APIs */
- static inline int led_control_open( const struct hw_module_t* module,
- struct led_control_device_t** device) {
- return module->methods->open(module,
- LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
- //这个过程非常重要,jni通过 LED_HARDWARE_MODULE_ID找到对应的stub
- }
- static jboolean mokoid_init(JNIEnv *env, jclass clazz)
- {
- led_module_t* module;
- LOGI("jni init-----------------------." );
- if (hw_get_module(LED_HARDWARE_MODULE_ID, ( const hw_module_t**)&module) == 0) {
- //根据LED_HARDWARE_MODULE_ID找到 hw_module_t,参考hal层的实现
- LOGI("LedService JNI: LED Stub found." );
- if (led_control_open(&module->common, &sLedDevice) == 0) {
- //通过hw_module_t找到 led_control_device_t
- LOGI("LedService JNI: Got Stub operations." );
- return 0;
- }
- }
- LOGE("LedService JNI: Get Stub operations failed." );
- return -1;
- }
- /*
- * Array of methods.
- * Each entry has three fields: the name of the method, the method
- * signature, and a pointer to the native implementation.
- */
- static const JNINativeMethod gMethods[] = {
- { "_init" , "()Z" , ( void *)mokoid_init }, //Framework层调用_init时促发
- { "_set_on" , "(I)Z" , ( void *)mokoid_setOn },
- { "_set_off" , "(I)Z" , ( void *)mokoid_setOff },
- };
- /*
- *JNINativeMethod是jni层注册的方法,Framework层可以使用这些方法
- *_init 、_set_on、_set_off是在 Framework中调用的方法名称,函数的类型及返回值如下:
- *()Z 无参数 返回值为bool型
- * (I)Z 整型参数 返回值为bool型
- */
- static int registerMethods(JNIEnv* env) {
- static const char * const kClassName =
- "com/mokoid/server/LedService" ; //注意:必须和你Framework层的service类名相同
- jclass clazz;
- /* look up the class */
- clazz = env->FindClass(kClassName);
- if (clazz == NULL) {
- LOGE("Can't find class %s/n" , kClassName);
- return -1;
- }
- /* register all the methods */
- if (env->RegisterNatives(clazz, gMethods,
- sizeof (gMethods) / sizeof (gMethods[0])) != JNI_OK)
- {
- LOGE("Failed registering methods for %s/n" , kClassName);
- return -1;
- }
- /* fill out the rest of the ID cache */
- return 0;
- }
- jint JNI_OnLoad(JavaVM* vm, void * reserved) { //Framework层加载jni库时调用
- JNIEnv* env = NULL;
- jint result = -1;
- LOGI("JNI_OnLoad LED" );
- if (vm->GetEnv(( void **) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("ERROR: GetEnv failed/n" );
- goto fail;
- }
- assert(env != NULL);
- if (registerMethods(env) != 0) { //注册你的JNINativeMethod
- LOGE("ERROR: PlatformLibrary native registration failed/n" );
- goto fail;
- }
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
- fail:
- return result;
- }
( 3 ) service ( 属于 Framework 层 )
文件:frameworks/base/service/java/com/mokoid/server/LedService.java
- package com.mokoid.server;
- import android.util.Config;
- import android.util.Log;
- import android.content.Context;
- import android.os.Binder;
- import android.os.Bundle;
- import android.os.RemoteException;
- import android.os.IBinder;
- import mokoid.hardware.ILedService;
- public final class LedService extends ILedService.Stub {
- //对于这种直接模式不需要进程通讯,所以可以不加 extends ILedService.Stub,此处加上主要是为了后面的第二种模式.
- static {
- System.load("/system/lib/libmokoid_runtime.so" ); //加载jni的动态库
- }
- public LedService() {
- Log.i("LedService" , "Go to get LED Stub..." );
- _init();
- }
- /*
- * Mokoid LED native methods.
- */
- public boolean setOn( int led) {
- Log.i("MokoidPlatform" , "LED On" );
- return _set_on(led);
- }
- public boolean setOff( int led) {
- Log.i("MokoidPlatform" , "LED Off" );
- return _set_off(led);
- }
- private static native boolean _init(); //声明jni库可以提供的方法
- private static native boolean _set_on( int led);
- private static native boolean _set_off( int led);
- }
( 4 ) APP 测试程序 (属于 APP 层 )
文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java
- package com.mokoid.LedClient;
- import com.mokoid.server.LedService;// 导入Framework层的LedService
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.TextView;
- public class LedClient extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Call an API on the library.
- LedService ls = new LedService(); //实例化LedService
- ls.setOn(1); //通过LedService提供的方法,控制底层硬件
- ls.setOff(2);
- TextView tv = new TextView( this );
- tv.setText("LED 1 is on. LED 2 is off." );
- setContentView(tv);
- }
- }
5 、第二种方法 : 经过 Manager 调用 service
HAL 、 JNI 两层和第一种方法一样 , 所以后面只分析其他的层次。
(1 )Manager ( 属于 Framework 层 )
APP 通过这个 Manager 和 service 通讯。
文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java
- package mokoid.hardware;
- import android.content.Context;
- import android.os.Binder;
- import android.os.Bundle;
- import android.os.Parcelable;
- import android.os.ParcelFileDescriptor;
- import android.os.Process;
- import android.os.RemoteException;
- import android.os.Handler;
- import android.os.Message;
- import android.os.ServiceManager;
- import android.util.Log;
- import mokoid.hardware.ILedService;
- /*
- * Class that lets you access the Mokoid LedService.
- */
- public class LedManager
- {
- private static final String TAG = "LedManager" ;
- private ILedService mLedService;
- public LedManager() {
- mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led" ));
- /*
- *这一步是关键,利用ServiceManager获取到LedService,从而调用它提供的方法。这要求 LedService必
- * 须已经添加到了ServiceManager中,这个过程将在App中的一个service进程中完成。
- */
- if (mLedService != null ) {
- Log.i(TAG, "The LedManager object is ready." );
- }
- }
- public boolean LedOn( int n) {
- boolean result = false ;
- try {
- result = mLedService.setOn(n);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in LedManager.LedOn:" , e);
- }
- return result;
- }
- public boolean LedOff( int n) {
- boolean result = false ;
- try {
- result = mLedService.setOff(n);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in LedManager.LedOff:" , e);
- }
- return result;
- }
- }
因为LedService 和LedManager 在不同的进 程,所以要考虑到进程通讯的问题。Manager 通过增加一个aidl 文件来描述通讯接口。
文件 :mokoid-read-only/frameworks/base/core/java/mokoid/hardware/ILedService.aidl
- package mokoid.hardware;
- interface ILedService
- {
- boolean setOn(int led);
- boolean setOff(int led);
- }
- //系统的aidl工具会将ILedService.aidl文件ILedService.java文件,实现了 ILedService
(2 )SystemServer ( 属于 APP 层 )
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java
- package com.mokoid.LedTest;
- import com.mokoid.server.LedService;
- import android.os.IBinder;
- import android.os.ServiceManager;
- import android.util.Log;
- import android.app.Service;
- import android.content.Context;
- import android.content.Intent;
- public class LedSystemServer extends Service {
- //注意这里的Service是APP中的概念,代表一个后台进 程。注意区别和Framework中的service的概念。
- @Override
- public IBinder onBind(Intent intent) {
- return null ;
- public void onStart(Intent intent, int startId) {
- Log.i("LedSystemServer" , "Start LedService..." );
- /* Please also see SystemServer.java for your interests. */
- LedService ls = new LedService();
- try {
- ServiceManager.addService("led" , ls); // 将LedService添加到ServiceManager中
- } catch (RuntimeException e) {
- Log.e("LedSystemServer" , "Start LedService failed." );
- }
- }
- }
(3 )APP 测试程序 ( 属于 APP 层 )
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java
- package com.mokoid.LedTest;
- import mokoid.hardware.LedManager;
- import com.mokoid.server.LedService;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.TextView;
- import android.widget.Button;
- import android.content.Intent;
- import android.view.View;
- public class LedTest extends Activity implements View.OnClickListener {
- private LedManager mLedManager = null ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Start LedService in a seperated process.
- startService(new Intent( "com.mokoid.systemserver" )); //开启后台进程
- Button btn = new Button( this );
- btn.setText("Click to turn LED 1 On" );
- btn.setOnClickListener(this );
- setContentView(btn);
- }
- public void onClick(View v) {
- // Get LedManager.
- if (mLedManager == null ) {
- Log.i("LedTest" , "Creat a new LedManager object." );
- mLedManager = new LedManager(); //实例化Framework层中的Manager
- }
- if (mLedManager != null ) {
- Log.i("LedTest" , "Got LedManager object." );
- }
- /** Call methods in LedService via proxy object
- * which is provided by LedManager.
- */
- mLedManager.LedOn(1);
- TextView tv = new TextView( this );
- tv.setText("LED 1 is On." );
- setContentView(tv);
- }
- }
五、实验中需要注意的问题
将下载后的源码放到你的 android 源码目录下 , 然后编译系统。本实验用的android版本为2.1。实验 的过程中大致出现过以下几个问题:
1、 目 标 系 统 中没有生成 LedClient.apk或LedTest.apk 应 用程序
编 译完成后,没有在目标系统的system/app/目录下找到LedClient.apk或LedTest应用程序。只有通过单独编译LedClient 或LedTest才能在目标目录中生成。方法如下:
#mmm mokoid-read-only/apps/LedTest/
检 查原因后发现mokoid-read-only/apps/LedTest/Android.mk
LOCAL_MODULES_TAGS :=user
而 我们的s5pc100系统在配置时tapas时选择的是eng,所以没有装载到目标系统
所 以修改LedTest和LedClient的Android.mk
LOCAL_MODULES_TAGS :=user eng
再次编译即可自动装载到目标系统/system/app /目录下。
2、 启 动 后没有 图标 ,找不到 应用 程序
目标 系统启动后找不到两个应用程序的图标。 仔 细阅读 logcat 输 出的信息 发现 :
E/PackageManager( 2717): Package com.mokoid.LedClient requires unavailable shared library com.mokoid.server; failing!
原因是 找不到 com.mokoid.server 。 检查mokoid-read- only/frameworks/base/Android.mk发现系统将LedManager和LedService编译成 mokoid.jar 库 文件。 为了让应用程序可以访问到这个库,需要通过 com.mokoid.server.xml 来设定其对应关系。解决方法:拷贝 com.mokoid.server.xml 到目标系统的system/etc/permissions/ 目 录下
此 时两个应用的程序的图标都正常出现了。
3 、 提示找不到 JNI_OnLoad
按照以前的实验加入下列代码:
- static int registerMethods(JNIEnv* env) {
- static const char * const kClassName = "com/mokoid/server/LedService" ;
- jclass clazz;
- /* look up the class */
- clazz = env->FindClass(kClassName);
- if (clazz == NULL) {
- LOGE("Can't find class %s/n" , kClassName);
- return -1;
- }
- /* register all the methods */
- if (env->RegisterNatives(clazz, gMethods,
- sizeof (gMethods) / sizeof (gMethods[0])) != JNI_OK)
- {
- LOGE("Failed registering methods for %s/n" , kClassName);
- return -1;
- }
- /* fill out the rest of the ID cache */
- return 0;
- }
- /*
- * This is called by the VM when the shared library is first loaded.
- */
- jint JNI_OnLoad(JavaVM* vm, void * reserved) {
- JNIEnv* env = NULL;
- jint result = -1;
- LOGI("JNI_OnLoad LED" );
- if (vm->GetEnv(( void **) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("ERROR: GetEnv failed/n" );
- goto fail;
- }
- assert(env != NULL);
- if (registerMethods(env) != 0) {
- LOGE("ERROR: PlatformLibrary native registration failed/n" );
- goto fail;
- }
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
- fail:
- return result;
- }
4 、 需要 针对 你的目 标 平台修改HAL的Makefile
修 改mokoid-read-only/hardware/modules/led/Android.mk
LOCAL_MODULE := led.default
5 、在 eclipse 中 编译 不了 LedSystemServer.java
原因是程序中要用到 ServiceManager.addService,这需要系统权限。
解决方法可以把应用程序放入Android 源码中编译,并确保以下两点:
(1 ) 在应用程序的 AndroidManifest.xml 中的 manifest 节点中加入 android:sharedUserId="android.uid.system" 这个属性。
(2 ) 修改 Android 加入 LOCAL_CERTIFICATE := platform.
当 然: mokoid工程源码中已经 做了这些。
(2) 经过 Manager调用service
此贴是对刘洪涛老师大作的转载,如有冒犯,敬请原谅