这个现实在之前没有电池的项目中是出现过的,但是那个是没有电池突然断电引起而有数据正在写入EMMC的,而之前是reboot,reboot应该是要关闭或暂停所有的线程保证没有写EMMC操作才对啊,郁闷。
没办法出现了就出现了,看看android的reboot做了什么吧,baidu一下,有很多,贴过流程出来:
framework
./base/core/java/com/android/internal/app/ShutdownThread.java
/**
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
* or {@link #shutdown(Context, boolean)} instead.
*
* @param reboot true to reboot or false to shutdown
* @param reason reason for reboot
*/
public static void rebootOrShutdown(boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
try {
Power.reboot(reason);
} catch (Exception e) {
Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
}
} else if (SHUTDOWN_VIBRATE_MS > 0) {
// vibrate before shutting down
Vibrator vibrator = new Vibrator();
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
} catch (Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try {
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch (InterruptedException unused) {
}
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
Power.shutdown();
}
./base/core/jni/android_os_Power.cpp 不一样
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
{
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}
extern int go_recovery(void);
static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
{
if (reason == NULL) {
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
const char *chars = env->GetStringUTFChars(reason, NULL);
//android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
go_recovery();
android_reboot(ANDROID_RB_RESTART, 0, 0);
env->ReleaseStringUTFChars(reason, chars); // In case it fails.
}
jniThrowIOException(env, errno);
}
ANDOID_ROOT\system\core\libcutils\android_reboot.c
int android_reboot(int cmd, int flags, char *arg)
{
int ret;
if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
sync();
if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
remount_ro();
switch (cmd) {
case ANDROID_RB_RESTART:
ret = reboot(RB_AUTOBOOT);
break;
case ANDROID_RB_POWEROFF:
ret = reboot(RB_POWER_OFF);
break;
case ANDROID_RB_RESTART2:
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);
break;
default:
ret = -1;
}
return ret;
}
android4.0/frameworks/base/core/jni/misc_rw.cpp
/* force the next boot to recovery */
int go_recovery(void){
LOGE("go_recovery =================\n");
struct bootloader_message boot, temp;
memset(&boot, 0, sizeof(boot));
strcpy(boot.command, "boot-recovery");
if (set_bootloader_message_block(&boot, MISC_DEVICE) )
return -1;
//read for compare
memset(&temp, 0, sizeof(temp));
if (get_bootloader_message_block(&temp, MISC_DEVICE))
return -1;
if( memcmp(&boot, &temp, sizeof(boot)) )
return -1;
LOGE("go_recovery ++++++++++++++++++++++\n");
return 0;
}
从上面可以看到重启之前是会把系统mount readonly的啊:
remount_ro();
那为什么还会有问题? 看来问题是出在remount_ro();里面了。看里面的代码
static void remount_ro(void)
{
int fd, cnt = 0;
/* Trigger the remount of the filesystems as read-only,
* which also marks them clean.
*/
fd = open("/proc/sysrq-trigger", O_WRONLY);
if (fd < 0) {
return;
}
write(fd, "u", 1);
close(fd);
/* Now poll /proc/mounts till it's done */
while (!remount_ro_done() && (cnt < 50)) {
usleep(100000);
cnt++;
}
return;
}
/proc/sysrq-trigger
这是个只读的节点可以,让系统重启,重新mount等一系列操作,但它是异步的,所以后面有个检测和等待,估计是等的时间不够长(等了5S),加长到一分钟试试。