「System Property」是儲存資料常用的方式,如同「Windows Registry」。它的 APIs 散佈在 Android codebase 的各個角落:.mk、.rc、.java、.c.cpp 都找的到。簡單來說,
System Property 分為「get」和「set」兩種方法,「get」相對而言就容易許多,因為不需要去檢查權限,code flow 只要呼叫到 libcutils 的 property_get 即可。所以底下只討論「set」。
由上圖得知,send_prop_msg 會透過 socket 將 cmd message 送給 INIT,當 INIT 接收到後,會呼叫 handle_property_set_fd 來做處理,該函式就會呼叫 check_perms 檢查權限,這也是為什麼有時候設定屬性會失敗的原因。check_perms 參考底下的 ACL (Access Control List) 做判斷:
<PATH>
system/core/init/property_service.c
struct {
const char *prefix;
unsigned int uid;
unsigned int gid;
} property_perms[] = {
{ "net.rmnet0.", AID_RADIO, 0 },
{ "net.usb", AID_RADIO, 0 },
{ "net.gprs.", AID_RADIO, 0 },
{ "net.ppp", AID_RADIO, 0 },
{ "ril.", AID_RADIO, 0 },
{ "gsm.", AID_RADIO, 0 },
{ "persist.radio", AID_RADIO, 0 },
{ "net.dns", AID_RADIO, 0 },
{ "net.", AID_SYSTEM, 0 },
{ "dev.", AID_SYSTEM, 0 },
{ "runtime.", AID_SYSTEM, 0 },
{ "hw.", AID_SYSTEM, 0 },
{ "sys.", AID_SYSTEM, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
{ "vpn.", AID_SYSTEM, 0 },
{ "vpn.", AID_VPN, 0 },
{ "debug.", AID_SHELL, 0 },
{ "log.", AID_SHELL, 0 },
{ "service.adb.root", AID_SHELL, 0 },
{ "service.adb.tcp.port", AID_SHELL, 0 },
{ "persist.sys.", AID_SYSTEM, 0 },
{ "persist.service.", AID_SYSTEM, 0 },
{ "persist.security.", AID_SYSTEM, 0 },
{ NULL, 0, 0 }
};
「check_perms」檢查的流程為:
- 如果 UID 為 ROOT .. PASS。
- 如果屬性為 ro 開頭,就接續判斷 ro. 之後的字串。
- 和 ACL 一一比對,prefix 要相同、且 uid/gid 有一個相同 .. PASS。
底下是 uid/gid 定義的地方
<PATH>
system/core/include/private/android_filesystem_config.h
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
...
...
static const struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
...
};
之前為了在 BluetoothService.java (
UID/GID 皆為 system) 設定屬性,定義了 persist.bluetooth.a2dp 和 audioflinger.bluetooth.a2dp,但怎麼設定都設定不動,後來胡亂地嘗試
persist.service.bluetooth.a2dp 就成功了,回過頭來看,就是因為滿足 ACL 的要求啦!
如果自行定義的 prefix 可以正常存取,
要嘛 UID/GID 為 ROOT;不然就只能唯讀。最後補充一點,在
/default.prop 這個檔案內看到的屬性,是 makefile 中由 ADDITIONAL_DEFAULT_PROPERTIES 這個變數產生;而
/system/build.prop 的是 build/tools/buildinfo.sh 和以下這段所產生。
ADDITIONAL_BUILD_PROPERTIES :=
$(ADDITIONAL_BUILD_PROPERTIES) \
$(PROPERTY_PROPERTY_OVERRIDES)
參考資料