Android启动时在加密界面后进恢复模式分析
异常进recovery前面已经分析过主要是persist进程crash too many,所以导致进恢复模式,显示"Can't load Android system"。
现在又出现这个恢复界面,是在刷完版本第一次开机加密时进入,看离线logcat,竟然没有"FACTORY_RESET"记录,难道和加密有关?
上OpenGrok搜下prompt_and_wipe_data:
/bootable/recovery/
H A D recovery.cpp 96 { "prompt_and_wipe_data", no_argument, NULL, 0 },
149 * --prompt_and_wipe_data - prompt the user that data is corrupt,
764 static bool prompt_and_wipe_data(Device* device) { function
1486 } else if (option == "prompt_and_wipe_data") {
1631 if (!prompt_and_wipe_data(device)) {
/system/core/init/
H A D builtins.cpp 263 "--prompt_and_wipe_data",
/frameworks/base/core/java/android/os/
H A D RecoverySystem.java 902 bootCommand(context, null, "--prompt_and_wipe_data", reasonArg, localeArg);
除了java外,还有system也会call,实际上是两处:
./core/init/builtins.cpp:291: {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
./core/init/builtins.cpp:1004: reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
看下code:
if (e4crypt_is_native()) {
LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
...
if (e4crypt_is_native()) {
if (e4crypt_set_directory_policy(args[1].c_str())) {
return reboot_into_recovery(
{"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
}
}
log里没有发现"Rebooting into recovery, reason: " ,lets check e4crypt_is_native
:
bool e4crypt_is_native() {
char value[PROPERTY_VALUE_MAX];
property_get("ro.crypto.type", value, "none");
return !strcmp(value, "file");
}
系统属性ro.crypto.type
要是file才会触发,看下项目的:
xxx:/ # getprop ro.crypto.type
block
很明显不是嘛,我去,那是什么导致进入的?有个线索是recovery log会记录reason,reason会保存到cache分区,来看bootable/recovery.cpp:
int main(int argc, char **argv) {
...
printf("reason is [%s]\n", reason);
...
}
static void copy_logs() {
// Always write to pmsg, this allows the OTA logs to be caught in logcat -L
copy_log_file_to_pmsg(TEMPORARY_LOG_FILE, LAST_LOG_FILE);
copy_log_file_to_pmsg(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE);
// We can do nothing for now if there's no /cache partition.
if (!has_cache) {
return;
}
ensure_path_mounted(LAST_LOG_FILE);
ensure_path_mounted(LAST_KMSG_FILE);
rotate_logs(LAST_LOG_FILE, LAST_KMSG_FILE);
// Copy logs to cache so the system can find out what happened.
copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
save_kernel_log(LAST_KMSG_FILE);
但是我们启用了OTA A/B系统把cache分区移除了,其实google在A/B启用后对cache分区的要求是可选的:
cache: The cache partition stores temporary data and is optional if a device uses A/B updates. The cache partition doesn't need to be writable from the bootloader, only erasable. The size depends on the device type and the availability of space on userdata. Currently 50MB-100MB should be ok.
目前9.0 recovery log默认还是存在cache分区的,所以建议在A/B使能后保留cache分区,当然你把log存储path改到/data/misc/recovery也行,参考README.md:
Running the manual tests
recovery-refresh
andrecovery-persist
executables exist only on systems without
/cache partition. And we need to follow special steps to run tests for them.
看下recovery-persist.cpp:
static const char *LAST_LOG_FILE = "/data/misc/recovery/last_log";
static const char *LAST_KMSG_FILE = "/data/misc/recovery/last_kmsg";
...
ssize_t logsave(
log_id_t /* logId */,
char /* prio */,
const char *filename,
const char *buf, size_t len,
void * /* arg */) {
std::string destination("/data/misc/");
destination += filename;
...
/*
* TBD: Future location to move content from
* /cache/recovery to /data/misc/recovery/
*/
so, 没有cache分区可以转到/data/misc/recovery下。
懒得改了,这个问题在user版本下出现,对应的userdebug死活出不来,没有log没有证据啊。换个新的userdebug版本竟然出现了,adb还在,赶紧抓下,发现还是persist process crash too many导致的。
为了帮助定位问题,其实可以在屏幕上把reason打出来, rt?
本站采用CC BY-NC-SA 4.0进行许可 | 转载请注明原文链接 - Android启动时在加密界面后进恢复模式分析
我现在进入了这个模式,请问怎么找原因
抓logcat分析,可能的原因文章也提了。