赞
踩
refer:http://blog.csdn.net/leerobin83/article/details/7162751
资料:
https://developer.android.com/intl/zh-CN/reference/android/os/PowerManager.html
1. 在PowerManager的API文档中,给出了一个关机/重启接口:
接口的作用就是重启设备,而且,就算重启成功了也没有返回值。
需要包含REBOOT权限,也就是android.permission.REBOOT
唯一参数reason代表需要的特定重启模式,比如recovery,当然也可以为null。
重启的实现在run()中,因为ShutdownThread是Thread的扩展,所以run会自动运行,如下。
/**
* 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() {
checkShutdownFlow();
while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
stMgr.saveStates(mContext);
stMgr.enterShutdown(mContext);
running();
}
if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {
stMgr.enterShutdown(mContext);
running();
}
}
public void running() {
如上所叙述,在重启前会将重启原因写入sys.shutdown.requested,如果没有则为空,如果是安全模式还会将persist.sys.safemode置1,之后会进行一些关机前的预处理,关闭ActivityManager以及MountService,最终调用rebootOrShutdown进行关机操作。
======>>>>>>android2中的rebootOrShutdown
如果重启,则调用PowerManagerService的lowLevelReboot函数,参数就是传递下来的reason,稍后分析。
如果不是重启,即mReboot=false,那就是需要关机了,在shutdown函数中就能够知道。如下所示:
但是在代码逻辑上看,无论如何,最后都会调用一下lowLevelShutdown函数,也就是关机。
逻辑上,这里可能是个问题,但是实际中,如果重启操作能够调用成功的话,整个系统都重启了,后边的代码当然不可能执行到了。
======>>>>>>android4.4中的rebootOrShutdown
{ android 4.4中的rebootOrShutdown---解析
public static void rebootOrShutdown(boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
if ( (reason != null) && reason.equals("recovery") ) {
delayForPlayAnimation();
}
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) {
}
}
delayForPlayAnimation();
// Shutdown power
// power off auto test, don't modify
Log.i(TAG, "Performing low-level shutdown...");
//PowerManagerService.lowLevelShutdown();已经注释掉了
//add your func: HDMI off
//add for MFR
try {
if (ImHDMI == null)
ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);
} catch (Exception e) {
e.printStackTrace();
}
ImHDMI.hdmiPowerEnable(false);
//unmout data/cache partitions while performing shutdown
SystemProperties.set("ctl.start", "shutdown");直接关机shutdown操作
/* sleep for a long time, prevent start another service */
try {
Thread.currentThread().sleep(Integer.MAX_VALUE);
} catch ( Exception e) {
Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");
}
}
}
目光转回PowerManagerService 中进行的lowLevelReboot()调用。。。。
很熟悉的字样native,是JNI调用了:
===>>>>>android 4.4 中的lowLevelShutdown 以及 lowLevelReboot
public static void lowLevelShutdown() {
SystemProperties.set("sys.powerctl", "shutdown");直接关机
}
/**
* Low-level function to reboot the device. On success, this function
* doesn't return. If more than 5 seconds passes from the time,
* a reboot is requested, this method returns.
*
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
*/
public static void lowLevelReboot(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "reboot," + reason);///重启
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
【注解:】
关机流程中最后是通过修改Android属性进行关机操作(SystemProperties.java通过JNI调用访问系统属性)。
当然我们也可以通过adb命令修改Android系统属性执行关机操作,例如adb shell setpro sys.powerctl shutdown。
这里我们简单介绍下修改Android属性关机的原理或流程。
native_set()--->SystemProperties_set()
这是SystemProperties.java类中设置系统函数的方法。
可以看到无论是关机还是重启,都是调用android_reboot来实现的,只是参数不一样而已。
int android_reboot(int cmd, int flags, char *arg)
{
int ret;
sync();
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;
}
接下来才是对参数的解析处理:
1)普通重启 ANDROID_RB_RESTART, reason = RB_AUTOBOOT;
2)关机 ANDROID_RB_POWEROFF, 无需reason,直接调用reboot进行关机;
3)带参数的特殊重启 ANDROID_RB_RESTART2, reason 将为默认值 -1
注解1:在有的android版本里,这里又会出现一个#ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON,如果定义了它,则无论上层传下来的参数是什么样的,最终都只是普通重启而已。定义它的方式是在BoardConfig.mk中加入TARGET_RECOVERY_PRE_COMMAND_CLEAR_REASON := true,应该有厂商会喜欢这么做的,毕竟除了普通重启,都可能带给用户一定的风险。最后会对reason进行一个检测,那么通过上边的分析,其实只有带参数的特殊重启才会为-1,而不等于-1的情况中有普通重启和关机,而关机已经自行解决了……所以,不等于-1的情况到了这里也只有普通重启了。最终这里就是区分普通重启与特殊重启的地方了。
注解2: 这里再插入一个问题,其他的几个cmd都是什么值呢?答案在bionic/libc/include/sys/reboot.h中:
先来看reboot函数,按照往常的经验,reboot最终一定会调用到__reboot的。
这里用一些篇幅简要介绍syscall,以后遇到类似的东西更好追踪一些。
第七步中的__reboot在arm架构的实现是这样的(bionic/libc/arch-arm/syscalls/__reboot.S)
/home/tonylau/tony-workspace/v387-debug/my-ap/bionic/libc/arch-arm/syscalls/__reboot.S
已经找到了内核中的对应映射,那么下一步就要去找寻真正的实现函数了,在include/asm-generic/unistd.h(/home/tonylau/tony-workspace/v387-debug/my-ap/prebuilts/ndk/9/platforms/android-4/arch-arm/usr/include/asm/unistd.h)中可以找到内核对__NR_reboot的syscall函数映射,即
在进入这个文件前,我们先去include/linux/syscalls.h中查看一下sys_reboot的定义:
进入sys.c文件后,并没有找到名为sys_reboot的函数,而通过仔细查找,发现一个很有趣的函数,其定义为SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg),对比__reboot的参数,能够符合。究竟是不是这个函数?
同样在include/linux/syscalls.h文件中,能够找到这样几个定义:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。