Pages

2011年5月5日 星期四

System Property

「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」檢查的流程為:
  1. 如果 UID 為 ROOT .. PASS。
  2. 如果屬性為 ro 開頭,就接續判斷 ro. 之後的字串。
  3. 和 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)

參考資料

5 則留言:

dadadog 提到...
作者已經移除這則留言。
dadadog 提到...

請問從哪裡可以確認
BluetoothService.java 的 UID/GID 皆為 system?

因為從android_filesystem_config.h看到的AID_BLUETOOTH 1002 而不是
AID_SYSTEM 1000

還是說不是從這邊看出來呢?

Eric 提到...

挖兩年前的文章了, 我想想喔, 我記得是利用adb shell進去看被啟動的process的權限, 因為android開機啟動的服務, 都是利用system server這個服務去喚起, 而system server的權限是system/system, 所以被喚起的服務, 例如bluetooth service就會繼承system server的權限

Eric 提到...

在這邊對原文補充一下, 就是在定義屬性名稱的時候, 盡量以property_perms提供的pattern去命名, 否則可能會有失敗的情況發生(當然我也是有看到有root權限的init, 裡頭隨便設定一個屬性名稱也可以, 這部分我就不知道怎麼解釋了XDD)

Eric 提到...

android_filesystem_config.h我只是想要對照system/core/init/property_service.c裡頭的property_perms, 所以想說一併貼出來, bluetooth service不是用AID_BLUETOOTH做為他的權限

 
Blogger Templates