色々な端末の rooted で出てくることが多かった「 /data/local.prop に ro.kernel.qemu=1 」って書けば良いよ!ってやつ。
まず local.prop とはどこで定義されているのか
platform_bionic/libc/include/sys/_system_properties.h at master · android/platform_bionic · GitHub
ここで
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
こんな感じに定義されてて
platform_system_core-init-property_service.c at master · android-platform_system_core · GitHub
ここで
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
こんな感じに読み込まれてるわけです。
/system/build.prop → /system/default.prop → /data/local.prop の順番で読み込まれていますね。
わざわざオーバーライドって定義の名前に使うぐらいなので最後に上書きする感じになってます。
まあその後 load_persistent_properties() で /data/property/persist.* を使って上書きされちゃうんですが。ソレは今回の話とは微妙に違うので気にしないで下さい。
横道にそれますが、 /default.prop どこで読んでんだよ!!とお思いの諸兄
platform_system_core-init-init.c at master · android-platform_system_core · GitHub
ここで
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
if (!is_charger)
property_load_boot_defaults();INFO("reading config file\n");
init_parse_config_file("/init.rc");
こんな感じ。充電モードじゃなければ /default.prop 読み込みますよと。その後で /init.rc を読んでるのも見えますね。この順番の認識は重要です。その後読み込んだ init.rc の中身を action_for_each_trigger で実行しているのも重要です。
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);/* skip mounting filesystems in charger mode */
if (!is_charger) {
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
action_for_each_trigger("post-fs-data", action_add_queue_tail);
}queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action(check_startup_action, "check_startup");if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
}
ファイルシステムの準備から始まって boot という順番。これ init.rc を読み解く際に重要。
さて、ここで話が戻って property_service_init_action が呼ばれてるのが分かると思います。
これが先ほどの build.prop などの読み込み部分に繋がります。
ほら、各種 prop を読み込んだあとに init.rc の early-boot と boot が実行されていますね?
つまり、early-boot と boot に local.prop で書かれたらまずいことを無効化する setprop を書いておけば local.prop の qemu 芸は無効化できるんです。
また横道それた。
さて、ここからが本番。
platform_system_core-adb-adb.c at ics-mr1-release · android-platform_system_core · GitHub
これよ。これ。
/* run adbd in secure mode if ro.secure is set and
** we are not in the emulator
*/
property_get("ro.kernel.qemu", value, "");
if (strcmp(value, "1") != 0) {
property_get("ro.secure", value, "1");
if (strcmp(value, "1") == 0) {
// don’t run as root if ro.secure is set…
secure = 1;
ro.kernel.qemu=1 じゃない場合に ro.secure=1 だと secure=1 にしてますね。
つまり、ro.kernel.qemu=1 な場合は ro.secure=0 と同じ状態→ adb shell で繋いだらプロンプトが「#」になるということです(ソース追うの面倒になった)。
やったー rooted だー
qemu ってのは Android SDK で使ってるエミュレータです。開発環境なので adb で繋いだあと色々弄れるように元々 rooted なのですねー
ソース読むの時間かかったけど各種 prop などの読み込み順番はこんな感じっていうのはすっきりした。
さて、これと tmp 芸をあわせて次行こう
コメント
[…] ro.kernel.qemu=1 > /data/local.prop して再起動すれば adb shell で繋いだら # なのでどうにでもなりますね。 local.propを使用したrootedと、ついでに-.propなどについて考えるよ – 8796.jp管理日誌 […]
[…] そしてもうひとつ重要な穴は qemu 芸が使えてしまうことです。 […]