在 [Mokoid] 的 LedTest 范例里,找到 [AndroidManifest.xml] 档案。这个档案为应用程式的「交货清单」;在开发 LedTest 的过程中,我们加入了一个属性如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mokoid.LedTest" android:sharedUserId="android.uid.system">
原来,ServiceManager 会去检查应用程式的权限;Android 作业系统会根据 UID 做权限管制,这里所讲的 UID 就是 Linux 系统管理面所讨论的 User ID,即使用者 ID。在 [] 里,找到这段实作:
int svc_can_register(unsigned uid, uint16_t *name) { unsigned n; if ((uid == 0) || (uid == AID_SYSTEM)) return 1; for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++) if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name)) return 1; return 0; } int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len, void *ptr, unsigned uid) { struct svcinfo *si; // LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid); if (!ptr || (len == 0) || (len > 127)) return -1; if (!svc_can_register(uid, s)) { LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", str8(s), ptr, uid); return -1; } ... 涉及到权限管理的两个文件: AndroidManifest.xml 和 Android.mk AndroidManifest.xml 声明权限: <uses-permissionandroid:name="android.permission.ACCESS_SURFACE_FLINGER" /> <uses-permission android:name="android.permission.VIBRATE"/> 声明用户组 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.inputmethod.pinyin" android:sharedUserId="android.uid.system"> Android.mk 中通过证书来声明权限。 LOCAL_CERTIFICATE := platform 需要和manifest中的android:sharedUserId="android.uid.system" 对应起来。 platform 权限问题,最好运行在自己编译的系统上,才可以有次特权。 如果修改了应用的权限。因为老的应用和数据有关联,因此, 重新下载应用并且需要尝试做一个恢复出厂设置或者通过应用管理器删除应用关联的所有数据。 system uid = 1000 是特殊权限进程。 }
AID_SYSTEM 被定义为 1000,即 system server 的 UID。从上述的实作可以了解,ServiceManager 会去检查应用程式的 UID,当 UID 不符规定时,便无法执行 do_add_service()。
也就是:当应用程式的 UID 不是 1000 时,是没有权限新增 Android Service 的。所以,在 AndroidManifest.xml 里加上 android:sharedUserId 属性的目的在于此:将应用程式的 UID 定义为 android.uid.system 即 1000,程式即可具备新增 Android Service 的权限。
以 Mokoid 所提供的范例为例,「因为我们是在 Android 应用程式里启动 Android Service」,因此要特别留意这个部份。典型的新增 Android Service 做法是修改 frameworks/base/services/java/com/android/server/SystemServer.java 档案,但是,「因为 3M 分支维护策略的理念是尽量避免更动原始的 Android 程式码」,所以我们采取这种「Start LedService in a seperated process.」的做法。细节请参考 Mokoid 范例。