diff --git a/adb/services.c b/adb/services.c index c22ce17cc..7eab17a85 100644 --- a/adb/services.c +++ b/adb/services.c @@ -32,7 +32,7 @@ # include # endif #else -# include +# include #endif typedef struct stinfo stinfo; @@ -193,8 +193,7 @@ void reboot_service(int fd, void *arg) waitpid(pid, &ret, 0); } - ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, (char *)arg); + ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno)); writex(fd, buf, strlen(buf)); diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h new file mode 100644 index 000000000..0c79be7e3 --- /dev/null +++ b/include/cutils/android_reboot.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_ANDROID_REBOOT_H__ +#define __CUTILS_ANDROID_REBOOT_H__ + +__BEGIN_DECLS + +/* Commands */ +#define ANDROID_RB_RESTART 0xDEAD0001 +#define ANDROID_RB_POWEROFF 0xDEAD0002 +#define ANDROID_RB_RESTART2 0xDEAD0003 + +/* Flags */ +#define ANDROID_RB_FLAG_NO_SYNC 0x1 +#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2 + +int android_reboot(int cmd, int flags, char *arg); + +__END_DECLS + +#endif /* __CUTILS_ANDROID_REBOOT_H__ */ diff --git a/init/signal_handler.c b/init/signal_handler.c index 833e59df0..f89d05821 100644 --- a/init/signal_handler.c +++ b/init/signal_handler.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "init.h" #include "list.h" @@ -96,9 +96,7 @@ static int wait_for_one_process(int block) ERROR("critical process '%s' exited %d times in %d minutes; " "rebooting into recovery mode\n", svc->name, CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); - sync(); - __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, "recovery"); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); return 0; } } else { diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 3dc3d694a..b6c538212 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -109,7 +109,7 @@ else #!sim # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE := libcutils -LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c +LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c android_reboot.c ifeq ($(TARGET_ARCH),arm) LOCAL_SRC_FILES += arch-arm/memset32.S diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c new file mode 100644 index 000000000..33a7358ec --- /dev/null +++ b/libcutils/android_reboot.c @@ -0,0 +1,134 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Check to see if /proc/mounts contains any writeable filesystems + * backed by a block device. + * Return true if none found, else return false. + */ +static int remount_ro_done(void) +{ + FILE *f; + char mount_dev[256]; + char mount_dir[256]; + char mount_type[256]; + char mount_opts[256]; + int mount_freq; + int mount_passno; + int match; + int found_rw_fs = 0; + + f = fopen("/proc/mounts", "r"); + if (! f) { + /* If we can't read /proc/mounts, just give up */ + return 1; + } + + do { + match = fscanf(f, "%255s %255s %255s %255s %d %d\n", + mount_dev, mount_dir, mount_type, + mount_opts, &mount_freq, &mount_passno); + mount_dev[255] = 0; + mount_dir[255] = 0; + mount_type[255] = 0; + mount_opts[255] = 0; + if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) { + found_rw_fs = 1; + break; + } + } while (match != EOF); + + fclose(f); + + return !found_rw_fs; +} + +/* Remounting filesystems read-only is difficult when there are files + * opened for writing or pending deletes on the filesystem. There is + * no way to force the remount with the mount(2) syscall. The magic sysrq + * 'u' command does an emergency remount read-only on all writable filesystems + * that have a block device (i.e. not tmpfs filesystems) by calling + * emergency_remount(), which knows how to force the remount to read-only. + * Unfortunately, that is asynchronous, and just schedules the work and + * returns. The best way to determine if it is done is to read /proc/mounts + * repeatedly until there are no more writable filesystems mounted on + * block devices. + */ +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; +} + + +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; +} + diff --git a/toolbox/reboot.c b/toolbox/reboot.c index aebe18501..f8546de2d 100644 --- a/toolbox/reboot.c +++ b/toolbox/reboot.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include int reboot_main(int argc, char *argv[]) @@ -9,6 +9,7 @@ int reboot_main(int argc, char *argv[]) int ret; int nosync = 0; int poweroff = 0; + int flags = 0; opterr = 0; do { @@ -38,15 +39,16 @@ int reboot_main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if(!nosync) - sync(); + if(nosync) + /* also set NO_REMOUNT_RO as remount ro includes an implicit sync */ + flags = ANDROID_RB_FLAG_NO_SYNC | ANDROID_RB_FLAG_NO_REMOUNT_RO; if(poweroff) - ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL); + ret = android_reboot(ANDROID_RB_POWEROFF, flags, 0); else if(argc > optind) - ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]); + ret = android_reboot(ANDROID_RB_RESTART2, flags, argv[optind]); else - ret = reboot(RB_AUTOBOOT); + ret = android_reboot(ANDROID_RB_RESTART, flags, 0); if(ret < 0) { perror("reboot"); exit(EXIT_FAILURE); diff --git a/toolbox/wipe.c b/toolbox/wipe.c index 7e263fd44..650a0d664 100644 --- a/toolbox/wipe.c +++ b/toolbox/wipe.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #ifndef PATH_MAX @@ -63,7 +63,7 @@ int wipe_main (int argc, char *argv[]) wipe ("/system"); wipe ("/data"); fprintf(stdout, "Device nuked! Rebooting...\n"); - ret = reboot(RB_AUTOBOOT); + ret = android_reboot(ANDROID_RB_RESTART, 0, 0); if (ret < 0) { fprintf(stderr, "Reboot failed, %s\n", strerror(errno)); return 1;