在 [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。在 [frmeworks/base/cmds/servicemanager/service_manager.c] 裡,找到這段實作:
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; } ... }
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 範例。
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw