android 关机重启流程

https://developer.android.com/intl/zh-CN/reference/android/os/PowerManager.html

在PowerManager的API文档中,给出了一个关机/重启接口:
public void reboot (String reason)
对于这个接口的描述很简单,就是几句话。
接口的作用就是重启设备,而且,就算重启成功了也没有返回值。
需要包含REBOOT权限,也就是android.permission.REBOOT
唯一参数reason代表需要的特定重启模式,比如recovery,当然也可以为null。

JAVA 层:

1.frameworks/base/core/java/android/os/PowerManager.java
2.frameworks/base/core/java/android/os/IPowerManager.aidl
3.frameworks/base/services/java/com/android/server/PowerManagerService.java
4.frameworks/base/services/java/com/android/server/pm/ShutdownThread.java
5.frameworks/base/services/jni/com_android_server_PowerManagerService.cpp
---------------------》
6.system/core/libcutils/android_reboot.c
7.bionic/libc/unistd/reboot.c


kernle层

8.__reboot通过syscall来到内核
9.kernel/sys.c

java 层流程:

frameworks/base/core/java/android/os/PowerManager.java

    /** 
     * Reboot the device.  Will not return if the reboot is
     * successful.  Requires the {@link android.Manifest.permission#REBOOT}
     * permission.
     *
     * @param reason code to pass to the kernel (e.g., "recovery") to
     *               request special boot modes, or null.
     */
    public void reboot(String reason)
    {   
        try {
            mService.reboot(reason);
        } catch (RemoteException e) {
        }   
    } 

mService为IPowerManager Binder接口服务。

    /**
     * {@hide}
     */
    public PowerManager(IPowerManager service, Handler handler)
    {
        mService = service;
        mHandler = handler;
    }

frameworks/base/core/java/android/os/IPowerManager.aidl

interface IPowerManager
{
...
void reboot(String reason);
...
}

frameworks/base/services/java/com/android/server/PowerManagerService.java

    /**  
     * Reboot the device immediately, passing 'reason' (may be null)
     * to the underlying __reboot system call.  Should not return.
     */
    public void reboot(String reason)
    {    
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
 
        if (mHandler == null || !ActivityManagerNative.isSystemReady()) {
            throw new IllegalStateException("Too early to call reboot()");
        }    
 
        final String finalReason = reason;
        Runnable runnable = new Runnable() {
            public void run() {
                synchronized (this) {
                    ShutdownThread.reboot(getUiContext(), finalReason, false);
                }    
 
            }    
        };   
        // ShutdownThread must run on a looper capable of displaying the UI.
        mHandler.post(runnable);
 
        // PowerManager.reboot() is documented not to return so just wait for the inevitable.
        synchronized (runnable) {
            while (true) {
                try {
                    runnable.wait();
                } catch (InterruptedException e) { 
                }    
            }    
        }    
    }

frameworks/base/services/java/com/android/server/pm/ShutdownThread.java

    /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootReason = reason;
        shutdownInner(context, confirm);
    }

这里说明是需要重启,且不是安全模式,重启参数为传递下来的reason,shutdownInner的confirm参数是用来设置是否有确认提示框的,通过reboot接口调用重启是没有的,为false。

重启的实现在run()中,因为ShutdownThread是Thread的扩展,所以run会自动运行。
frameworks/base/services/java/com/android/server/pm/ShutdownThread.java

    /**
     * Makes sure we handle the shutdown gracefully.
     * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
     */ 
    public void run() {
        BroadcastReceiver br = new BroadcastReceiver() {
            @Override public void onReceive(Context context, Intent intent) {
                // We don't allow apps to cancel this, so ignore the result.
                actionDone();
            }
        };
 
        /*
         * Write a system property in case the system_server reboots before we
         * get to the actual hardware restart. If that happens, we'll retry at
         * the beginning of the SystemServer startup.
         */ 
        {   
            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
        }
 
        /*
         * If we are rebooting into safe mode, write a system property
         * indicating so.
         */ 
        if (mRebootSafeMode) {
            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
        }
        ...
        rebootOrShutdown(mReboot, mRebootReason);
    } 

在重启前会将重启原因写入sys.shutdown.requested,如果没有则为空,如果是安全模式还会将persist.sys.safemode置1,之后会进行一些关机前的预处理,关闭ActivityManager以及MountService,最终调用rebootOrShutdown进行关机操作。

    /**
     * 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 {
                PowerManagerService.lowLevelReboot(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 SystemVibrator();
            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...");
        PowerManagerService.lowLevelShutdown();
    }
}

如果确认重启,则调用PowerManagerService的lowLevelReboot函数,参数就是传递下来的reason,稍后分析。如果不是重启,即mReboot=false,那就是需要关机了,在shutdown函数中就能够知道。

    /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void shutdown(final Context context, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        shutdownInner(context, confirm);
    }

frameworks/base/services/java/com/android/server/PowerManagerService.java

    /**  
     * Low-level function to reboot the device.
     *
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @throws IOException if reboot fails for some reason (eg, lack of
     *         permission)
     */
    public static void lowLevelReboot(String reason) throws IOException {
        nativeReboot(reason);
    }  
 
    /**  
     * Low-level function turn the device off immediately, without trying
     * to be clean.  Most people should use
     * {@link com.android.server.pm.internal.app.ShutdownThread} for a clean shutdown.
     */
    public static void lowLevelShutdown() {
        nativeShutdown();
    } 

frameworks/base/services/jni/com_android_server_PowerManagerService.cpp

static JNINativeMethod gPowerManagerServiceMethods[] = { 
    /* name, signature, funcPtr */
    ...
    { "nativeShutdown", "()V",
            (void*) nativeShutdown },
    { "nativeReboot", "(Ljava/lang/String;)V",
            (void*) nativeReboot },
    ...
};
.................

static void nativeShutdown(JNIEnv *env, jobject clazz) {
    android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}
 
static void nativeReboot(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);
        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.
    }
    jniThrowIOException(env, errno);
}

可以看到无论是关机还是重启,都是调用android_reboot来实现的,只是参数不一样而已。

system/core/libcutils/android_reboot.c

int android_reboot(int cmd, int flags, char *arg)
{
    int ret = 0;
    int reason = -1;
 
#ifdef RECOVERY_PRE_COMMAND
    if (cmd == (int) ANDROID_RB_RESTART2) {
        if (arg && strlen(arg) > 0) {
            char cmd[PATH_MAX];
            sprintf(cmd, RECOVERY_PRE_COMMAND " %s", arg);
            system(cmd);
        }
    }
#endif
 
    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
        sync();
 
    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
        remount_ro();
 
    switch (cmd) {
        case ANDROID_RB_RESTART:
            reason = RB_AUTOBOOT;
            break;
 
        case ANDROID_RB_POWEROFF:
            ret = reboot(RB_POWER_OFF);
            return ret;
 
        case ANDROID_RB_RESTART2:
            // REBOOT_MAGIC
            break;
 
        default:
            return -1;
    }
 
#ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON
    reason = RB_AUTOBOOT;
#endif
 
    if (reason != -1)
        ret = reboot(reason);
    else
        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                           LINUX_REBOOT_CMD_RESTART2, arg);
 
    return ret;
}

以reboot recovery为例,arg即为recovery,所在在第五步的时候会传入ANDROID_RB_RESTART2。到了android_reboot函数中,会看到这样的定义#ifdef RECOVERY_PRE_COMMAND,即属于重启前会执行的命令,如果定义了就会执行。

下面也是做了一些关机重启前的预处理工作,sync()作用是将缓存中的信息写入磁盘,以免程序异常结束导致文件被损坏,linux系统关机前会做几次这样的动作;而remount_ro()作用是通过调用emergency_remount()强制将文件系统挂载为只读,不再允许任何写入操作,同时会通过检查/proc/mounts的设备状态来确认是否当前的所有写入工作已经完成,这个检查过程是阻塞操作。

接下来才是对参数的解析处理:

1)普通重启 ANDROID_RB_RESTART, reason = RB_AUTOBOOT;

2)关机 ANDROID_RB_POWEROFF, 无需reason,直接调用reboot进行关机;

3)带参数的特殊重启 ANDROID_RB_RESTART2, reason 将为默认值 -1

这里又出现一个#ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON,如果定义了它,则无论上层传下来的参数是什么样的,最终都只是普通重启而已。定义它的方式是在BoardConfig.mk中加入TARGET_RECOVERY_PRE_COMMAND_CLEAR_REASON := true,应该有厂商会喜欢这么做的,毕竟除了普通重启,都可能带给用户一定的风险。

最后会对reason进行一个检测,那么通过上边的分析,其实只有带参数的特殊重启才会为-1,而不等于-1的情况中有普通重启和关机,而关机已经自行解决了……所以,不等于-1的情况到了这里也只有普通重启了。最终这里就是区分普通重启与特殊重启的地方了。这里再插入一个问题,其他的几个cmd都是什么值呢?答案在bionic/libc/include/sys/reboot.h中:

#define RB_AUTOBOOT     LINUX_REBOOT_CMD_RESTART
#define RB_HALT_SYSTEM  LINUX_REBOOT_CMD_HALT
#define RB_ENABLE_CAD   LINUX_REBOOT_CMD_CAD_ON
#define RB_DISABLE_CAD  LINUX_REBOOT_CMD_CAD_OFF
#define RB_POWER_OFF    LINUX_REBOOT_CMD_POWER_OFF

bionic/libc/kernel/common/linux/reboot.h
#define LINUX_REBOOT_MAGIC1 0xfee1dead
#define LINUX_REBOOT_MAGIC2 672274793
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define LINUX_REBOOT_MAGIC2A 85072278
#define LINUX_REBOOT_MAGIC2B 369367448
#define LINUX_REBOOT_MAGIC2C 537993216
#define LINUX_REBOOT_CMD_RESTART 0x01234567
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF
#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
#define LINUX_REBOOT_CMD_KEXEC 0x45584543

bionic/libc/unistd/reboot.c
int reboot (int  mode) 
{
    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );
}

reboot(reason) -> reboot(RB_AUTOBOOT) -> __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, NULL )
__reboot通过syscall来到内核bionic/libc/arch-arm/syscalls/__reboot.S

ENTRY(__reboot)
    .save   {r4, r7} 
    stmfd   sp!, {r4, r7}
    ldr     r7, =__NR_reboot
    swi     #0  
    ldmfd   sp!, {r4, r7}
    movs    r0, r0
    bxpl    lr  
    b       __set_syscall_errno
END(__reboot)

bionic/libc/sys/linux-syscalls.h
#define __NR_reboot                       (__NR_SYSCALL_BASE + 88)

其被指定了一个固定的偏移量,在被调用的时候就是通过这个偏移量去内核中寻找对应的入口的,由此可见,内核中一定有着相同的定义,否则将不能成功调用。内核中对syscall偏移量的定义在内核源码中的arch/arm/include/asm/unistd.h,相关信息完全一致。

已经找到了内核中的对应映射,那么下一步就要去找寻真正的实现函数了,在include/asm-generic/unistd.h中可以找到内核对__NR_reboot的syscall函数映射,即

/* kernel/sys.c */
#define __NR_setpriority 140
__SYSCALL(__NR_setpriority, sys_setpriority)
#define __NR_getpriority 141
__SYSCALL(__NR_getpriority, sys_getpriority)
#define __NR_reboot 142
__SYSCALL(__NR_reboot, sys_reboot)

同时,能够发现如此温馨的一幕,内核已经指引我们下一步该去哪里寻找sys_reboot,即kernel/sys.c。

include/linux/syscalls.h

asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
                void __user *arg);

与__reboot的调用参数一致。

进入sys.c文件后,并没有找到名为sys_reboot的函数,而通过仔细查找,发现一个很有趣的函数,其定义为SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg),对比__reboot的参数,能够符合。究竟是不是这个函数?

同样在include/linux/syscalls.h文件中,能够找到这样几个定义:

#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
...
 
#define SYSCALL_DEFINEx(x, sname, ...)              \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
...
 
#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))


#define SYSCALL_DEFINE4(name, ...) \
    asmlinkage long sys##_name(__SC_DECL##4(__VA_ARGS__))


........

/*
 * Reboot system call: for obvious reasons only root may call it,
 * and even root needs to set up some magic numbers in the registers
 * so that some mistake won't make this reboot the whole machine.
 * You can also set the meaning of the ctrl-alt-del-key here.
 *
 * reboot doesn't sync: do that yourself before calling this.
 */
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
        void __user *, arg)
{
    char buffer[256];
    int ret = 0;
 
    /* We only trust the superuser with rebooting the system. */
    if (!capable(CAP_SYS_BOOT))
        return -EPERM;
 
    /* For safety, we require "magic" arguments. */
    if (magic1 != LINUX_REBOOT_MAGIC1 ||
        (magic2 != LINUX_REBOOT_MAGIC2 &&
                    magic2 != LINUX_REBOOT_MAGIC2A &&
            magic2 != LINUX_REBOOT_MAGIC2B &&
                    magic2 != LINUX_REBOOT_MAGIC2C))
        return -EINVAL;
 
    /* Instead of trying to make the power_off code look like
     * halt when pm_power_off is not set do it the easy way.
     */
    if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
        cmd = LINUX_REBOOT_CMD_HALT;
 
    mutex_lock(&reboot_mutex);
    switch (cmd) {
    case LINUX_REBOOT_CMD_RESTART:
        kernel_restart(NULL);
        break;
 
    case LINUX_REBOOT_CMD_CAD_ON:
        C_A_D = 1;
        break;
 
    case LINUX_REBOOT_CMD_CAD_OFF:
        C_A_D = 0;
        break;
 
    case LINUX_REBOOT_CMD_HALT:
        kernel_halt();
        do_exit(0);
        panic("cannot halt");
 
    case LINUX_REBOOT_CMD_POWER_OFF:
        kernel_power_off();
        do_exit(0);
        break;
 
    case LINUX_REBOOT_CMD_RESTART2:
        if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
            ret = -EFAULT;
            break;
        }
        buffer[sizeof(buffer) - 1] = '\0';
 
        kernel_restart(buffer);
        break;
 
#ifdef CONFIG_KEXEC
    case LINUX_REBOOT_CMD_KEXEC:
        ret = kernel_kexec();
        break;
#endif
 
#ifdef CONFIG_HIBERNATION
    case LINUX_REBOOT_CMD_SW_SUSPEND:
        ret = hibernate();
        break;
#endif
 
    default:
        ret = -EINVAL;
        break;
    }
    mutex_unlock(&reboot_mutex);
    return ret;
}

而pm_power_off为空的话,就把用户的关机命令转换为挂起:
arch/arm/kernel/process.c

/*
 * Function pointers to optional machine specific functions
 */
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);

pm_power_off = msm_pm_power_off;

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)
这个过程是用reboot_mutex互斥锁来进行保护的,以保证同一时间只可能有一个解析过程,避免冲突。

/*
 * Commands accepted by the _reboot() system call.
 *      
 * RESTART     Restart system using default command and mode.
 * HALT        Stop OS and give system control to ROM monitor, if any.
 * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
 * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
 * POWER_OFF   Stop OS and remove all power from system, if possible.
 * RESTART2    Restart system using given command string.
 * SW_SUSPEND  Suspend system using software suspend if compiled in.
 * KEXEC       Restart system using a previously loaded Linux kernel
 */     
        
#define LINUX_REBOOT_CMD_RESTART    0x01234567
#define LINUX_REBOOT_CMD_HALT       0xCDEF0123
#define LINUX_REBOOT_CMD_CAD_ON     0x89ABCDEF
#define LINUX_REBOOT_CMD_CAD_OFF    0x00000000 
#define LINUX_REBOOT_CMD_POWER_OFF  0x4321FEDC
#define LINUX_REBOOT_CMD_RESTART2   0xA1B2C3D4
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
#define LINUX_REBOOT_CMD_KEXEC      0x45584543

bionic/libc/include/sys/reboot.h 中可以看到android定义的启动方式
RESTART
POWER_OFF
RESTART2

最终实现

/**
 *  kernel_power_off - power_off the system
 *
 *  Shutdown everything and perform a clean system power_off.
 */
void kernel_power_off(void)
{
    kernel_shutdown_prepare(SYSTEM_POWER_OFF);
    if (pm_power_off_prepare)
        pm_power_off_prepare();
    disable_nonboot_cpus();
    syscore_shutdown();
    printk(KERN_EMERG "Power down.\n");
    kmsg_dump(KMSG_DUMP_POWEROFF);
    machine_power_off();
}
EXPORT_SYMBOL_GPL(kernel_power_off);

----------------------------------------------------------------------------------------
/**
 *  kernel_restart - reboot the system
 *  @cmd: pointer to buffer containing command to execute for restart
 *      or %NULL
 *
 *  Shutdown everything and perform a clean reboot.
 *  This is not safe to call in interrupt context.
 */
void kernel_restart(char *cmd)
{
    kernel_restart_prepare(cmd);
    if (!cmd)
        printk(KERN_EMERG "Restarting system.\n");
    else
        printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
    kmsg_dump(KMSG_DUMP_RESTART);
    machine_restart(cmd);
}
EXPORT_SYMBOL_GPL(kernel_restart);
void machine_restart(char *cmd)
{
    machine_shutdown();
    arm_pm_restart(reboot_mode, cmd);
}
...
void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
EXPORT_SYMBOL_GPL(arm_pm_restart);

对框架进行赋值,qcom 平台 845上已经不是这函数,自己查找
arm_pm_restart = msm_pm_restart;

下面是qcom 实现,每个平台不同

static void msm_pm_restart(char str, const char *cmd)
{       
    msm_rpcrouter_close();
    msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
 
    for (;;)
        ;
} 

可以在跟踪这个流程的过程中会发现,确实是有存在关机的相关接口的。那么关机该怎么用呢?
frameworks/base/services/java/com/android/serverBatteryService.java

        private final void shutdownIfNoPower() {
        // shut down gracefully if our battery is critically low and we are not powered.
        // wait until the system has booted before attempting to display the shutdown dialog.
        if (mBatteryLevel == 0 && !isPowered() && ActivityManagerNative.isSystemReady()) {
            Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
            intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent);
        }
    }

重启方式: 最后就是设定寄存器,Uboot 解析不同寄存器的值进入不同的启动模式

recovery 如果传下来的字符串是recovery那么,就在RTC寄存器里设置某个特定值,当uboot里读取RTC寄存器的时候如果获取了这个特定值,那就可以起recovery这个动作了。

Ref:https://blog.csdn.net/leerobin83/article/details/7162751

如何实现android 关机开机

上面主要讲到流程,在实际开发中, 主动调用系统开机关机如何做
(Ref:https://blog.csdn.net/luzhenrong45/article/details/42092007)
一. 发送系统广播方式
二. 通过init.rc启动系统服务来运行sh文件
三. Runtime调用Linux-shell
四 . PowerManager reboot以及反射调用PowerManagerService shutdown
五.使用ShutdownThread (尝试不成功,但想法觉得可行)

public static final String ACTION_REBOOT = "android.intent.action.REBOOT";
public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";

Intent.java位于源码/frameworks/base/core/java/android/content/Intent.java下面

//广播方式关机重启
case R.id.shutdown_btn1:
    Log.v(TAG, "broadcast->shutdown");
    Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
    intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
    //其中false换成true,会弹出是否关机的确认窗口
    startActivity(intent);
break;
case R.id.reboot_btn1:
    Log.v(TAG, "broadcast->reboot");
    Intent intent2 = new Intent(Intent.ACTION_REBOOT);
    intent2.putExtra("nowait", 1);
    intent2.putExtra("interval", 1);
    intent2.putExtra("window", 0);
    sendBroadcast(intent2);  
    break;

脚本方式,实际都是基于指令的

使用PowerManager 或ShutdownThread 都是基于关机流程

你可能感兴趣的:(android 关机重启流程)