Android关机流程
来源:互联网 发布:当日成交密度指标源码 编辑:程序博客网 时间:2024/05/14 05:45
转自:http://www.2cto.com/kf/201501/367859.html
ShutdownThread.java文件
stop playing music,因为后面可能要playing shutdown music.
代码如下:
private
static
void
beginShutdownSequence(Context context) {
....
//acquire audio focus to make the other apps to stop playing muisc
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(
null
,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
show system dialog to indicate phone is shutting down,如果没有关机动画的话,要show一个关机提示出来。
代码如下:
if
(!checkAnimationFileExist()) {
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
ProgressDialog pd =
new
ProgressDialog(context);
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
pd.setIndeterminate(
true
);
pd.setCancelable(
false
);
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
pd.show();
}
Hold the wakelock,make sure we never fall asleep again,抓锁防止机器关机过程中休眠
代码如下:
sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + -cpu);
//这个只是锁住cpu不进入休眠,但screen是off的,需full锁来保证screen常亮
sInstance.mCpuWakeLock.setReferenceCounted(
false
);
sInstance.mCpuWakeLock.acquire();
make sure the screen stays on,再抓一个full锁,防止屏幕半暗
代码如下:
sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.FULL_WAKE_LOCK, TAG + -screen);
//保持srceen常亮
sInstance.mScreenWakeLock.setReferenceCounted(
false
);
sInstance.mScreenWakeLock.acquire();
起一下新进程
sending shutdown broadcast,发出广播,通知各app该保存数据赶紧的,我要关机了
代码如下:
Intent intent =
new
Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
//发广播
UserHandle.ALL,
null
, br, mHandler,
0
,
null
,
null
);
shutdown activity manager,关闭activity manager,即关闭AppOpsService,UsageStatsService,BatteryStatsService
注意:android L 与KK在关闭UsageStatsService上有所区别
代码如下:
[ActivityManagerService.java]
final
IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService(activity));
if
(am !=
null
) {
try
{
am.shutdown(MAX_BROADCAST_TIME);
}
catch
(RemoteException e) {
}
}
shutdown package manager,保存app使用时间到 disk里,这是android L新增的功能。
代码如下:
[PackageManagerService.java]
final
PackageManagerService pm = (PackageManagerService)
ServiceManager.getService(
package
);
if
(pm !=
null
) {
pm.shutdown();
}
show shutdown animation,播放关机动画了
代码如下:
private
static
void
showShutdownAnimation() {
/*
* When boot completed, service.bootanim.exit property is set to 1.
* Bootanimation checks this property to stop showing the boot animation.
* Since we use the same code for shutdown animation, we
* need to reset this property to 0. If this is not set to 0 then shutdown
* will stop and exit after displaying the first frame of the animation
*/
SystemProperties.set(service.bootanim.exit,
0
);
SystemProperties.set(ctl.start, bootanim);
//也是用bootanim进程,跟开关动画一样的方式。
}
shutdown radio[NFC,BT,MODEM],注意这里关闭modem这块与andorid KK的不一样。
代码如下:
shutdownRadios(MAX_RADIO_WAIT_TIME);
shutdown MountService,特别这里会导致关机失败。
代码如下:
// Set initial variables and time out time.
mActionDone =
false
;
final
long
endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized
(mActionDoneSync) {
try
{
final
IMountService mount = IMountService.Stub.asInterface(
ServiceManager.checkService(mount));
if
(mount !=
null
) {
mount.shutdown(observer);
}
else
{
Log.w(TAG, MountService unavailable
for
shutdown);
}
}
catch
(Exception e) {
Log.e(TAG, Exception during MountService shutdown, e);
}
while
(!mActionDone) {
long
delay = endShutTime - SystemClock.elapsedRealtime();
if
(delay <=
0
) {
Log.w(TAG, Shutdown wait timed out);
break
;
}
try
{
mActionDoneSync.wait(delay);
}
catch
(InterruptedException e) {
}
}
}
走完上层关机流程,下面就要执行关机动作了。
代码如下:
public
static
void
rebootOrShutdown(
boolean
reboot, String reason) {
deviceRebootOrShutdown(reboot, reason);
if
(reboot) {
Log.i(TAG, Rebooting, reason: + reason);
PowerManagerService.lowLevelReboot(reason);
//重启
Log.e(TAG, Reboot failed, will attempt shutdown instead);
}
else
if
(SHUTDOWN_VIBRATE_MS >
0
) {
// vibrate before shutting down
Vibrator vibrator =
new
SystemVibrator();
try
{
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
}
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();
//关机
}
从代码上看始终会走到lowLevelShutdown(),但如果是重启就不会,lowLevelReboot()就停止了。
lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,其实都只是设置一个属性:SystemProperties.set(sys.powerctl, xxx);
正是这个动作触发关机流程往下走,这涉及到init进程的4大功能,请参考我的另一篇文章Android的init进程
sys.powerctl属性触发开关在init.rc定义
on property:sys.powerctl=*
powerctl ${sys.powerctl}
我们来解读这句话,on property:sys.powerctl=*表示当属性sys.powerctl设置为任何值是都会跑到这里,触发动作是powerctl ${sys.powerctl},这个动作的意思是调用powerctl指令,并把sys.powerctl的值传给它。powerctl指令在init进程会执行。
从下面的表可知,powerctl对应的操作是do_powerctl
[system/core/init/keywords.h]
KEYWORD(powerctl, COMMAND,
1
, do_powerctl)
do_powerctl的实现
代码如下:
[system/core/init/builtins.c]
int
do_powerctl(
int
nargs,
char
**args)
{
....
return
android_reboot(cmd,
0
, reboot_target);
}
它调用android_reboot()函数,实现如下:
[system/core/libcutils/android_reboot.c]
int
android_reboot(
int
cmd,
int
flags UNUSED,
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 = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);
break
;
default
:
ret = -
1
;
}
return
ret;
}
从这里看出它的主要工作:
sync() 回写block设备的内容,这是阻塞型操作。
remount_ro() 把block设备remount成ro,这里有个关键LOG:SysRq : Emergency Remount R/O,这是在logkit所能看到的最后一句LOG,因为remount成ro了,后面的LOG要通过last kmsg技术导出来。
reboot()或者syscall(__NR_reboot....,这点与android KK不同,这边直接用syscall功能,KK则通过汇编。
后面syscall(__NR_reboot...知道,直接调用了linux的__NR_reboot系统调用,这个系统调用会跑哪里?后面会讲。
reboot()这个函数实现如下:
[bionic/libc/bionic/reboot.cpp]
int
reboot(
int
mode) {
return
__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
}
调用了__reboot,它在汇编实现 如下:
[bionic/libc/arch-arm/syscalls/__reboot.S]
ENTRY(__reboot)
mov ip, r7
ldr r7, =__NR_reboot
//也跑到__NR_reboot系统调用
swi #
0
mov r7, ip
cmn r0, #(MAX_ERRNO +
1
)
bxls lr
neg r0, r0
b __set_errno_internal
END(__reboot)
__NR_reboot对应的内核入口在哪里?
如下:
[bionic/libc/kernel/uapi/asm-generic/unistd.h]
#define __NR_reboot
142
它在内核入口如下:
注:bionic/libc/kernel/uapi/asm-generic/unistd.h与kernel/include/uapi/asm-generic/unistd.h是对应的,方便以后代码追踪
[kernel/include/uapi/asm-generic/unistd.h]
#define __NR_reboot
142
__SYSCALL(__NR_reboot, sys_reboot)
__NR_reboot 映射到 sys_reboot
grep 下sys_reboot 找不到,其实在这里
用SYSCALL_DEFINE定义
[kernel/kernel/sys.c]
SYSCALL_DEFINE4(reboot,
int
, magic1,
int
, magic2, unsigned
int
, cmd,
void
__user *, arg)
{
struct pid_namespace *pid_ns = task_active_pid_ns(current);
char
buffer[
256
];
int
ret =
0
;
/* We only trust the superuser with rebooting the system. */
if
(!ns_capable(pid_ns->user_ns, 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;
/*
* If pid namespaces are enabled and the current task is in a child
* pid_namespace, the command is handled by reboot_pid_ns() which will
* call do_exit().
*/
ret = reboot_pid_ns(pid_ns, cmd);
if
(ret)
return
ret;
/* 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
] =
''
;
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;
}
有很多分支,我们只关心kernel_power_off()和kernel_restart()两函数就行
如下:
void
kernel_power_off(
void
)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
//关闭外设
if
(pm_power_off_prepare)
pm_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown();
//关闭syscore
printk(KERN_EMERG Power down.
);
//关键打印
kmsg_dump(KMSG_DUMP_POWEROFF);
machine_power_off();
}
void
kernel_restart(
char
*cmd)
{
kernel_restart_prepare(cmd);
//关闭外设
migrate_to_reboot_cpu();
syscore_shutdown();
//关闭syscore
if
(!cmd)
printk(KERN_EMERG Restarting system.
);
//关键打印
else
printk(KERN_EMERG Restarting system with command
'%s'
.
, cmd);
kmsg_dump(KMSG_DUMP_RESTART);
machine_restart(cmd);
}
都执行XX_prepare()函数
static
void
kernel_shutdown_prepare(
enum
system_states state)
{
blocking_notifier_call_chain(&reboot_notifier_list,
(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
system_state = state;
usermodehelper_disable();
device_shutdown();
}
void
kernel_restart_prepare(
char
*cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
usermodehelper_disable();
device_shutdown();
}
除了前面不同,都调用了device_shutdown()函数,关闭外设。
machine_power_off() machine_resestart()函数实现
void
machine_power_off(
void
)
{
preempt_disable();
smp_send_stop();
if
(pm_power_off)
pm_power_off();
//关机
}
void
machine_restart(
char
*cmd)
{
preempt_disable();
smp_send_stop();
/* Flush the console to make sure all the relevant messages make it
* out to the console drivers */
arm_machine_flush_console();
arm_pm_restart(reboot_mode, cmd);
//重启
/* Give a grace period for failure to restart of 1s */
mdelay(
1000
);
/* Whoops - the platform was unable to reboot. Tell the user! */
printk(Reboot failed -- System halted
);
local_irq_disable();
while
(
1
);
}
pm_power_offf() arm_pm_restart()都是一个函数指针
赋值如下:
[kernel/drivers/power/reset/msm-poweroff.c]
pm_power_off = do_msm_poweroff;
arm_pm_restart = do_msm_restart;
高通平台的关机代码与之前有所不同,现在文件msm-poweroff.c以前是restart.c。
do_msm_poweroff()与do_msm_restart()实现如下:
static
void
do_msm_poweroff(
void
)
{
....
pr_notice(Powering off the SoC
);
//关键打印
#ifdef CONFIG_MSM_DLOAD_MODE
set_dload_mode(
0
);
//关机,所以dloadmode是0
#endif
qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
//配置PMIC,是关机
.....
/* MSM initiated power off, lower ps_hold */
__raw_writel(
0
, msm_ps_hold);
//拉 PS_HOLD,执行关机动作。
mdelay(
10000
);
pr_err(Powering off has failed
);
return
;
}
static
void
do_msm_restart(
enum
reboot_mode reboot_mode,
const
char
*cmd)
...
pr_notice(Going down
for
restart now
);
//关键打印
msm_restart_prepare(cmd);
//重启准备前动作
#ifdef CONFIG_MSM_DLOAD_MODE
/*
* Trigger a watchdog bite here and if this fails,
* device will take the usual restart path.
*/
if
(WDOG_BITE_ON_PANIC && in_panic)
msm_trigger_wdog_bite();
#endif
....
halt_spmi_pmic_arbiter();
__raw_writel(
0
, msm_ps_hold);
//拉PS_HOLD重启
mdelay(
10000
);
}
msm_restart_prepare()实现
static
void
msm_restart_prepare(
const
char
*cmd)
{
#ifdef CONFIG_MSM_DLOAD_MODE
/* Write download mode flags if we're panic'ing
* Write download mode flags if restart_mode says so
* Kill download mode if master-kill switch is set
*/
set_dload_mode(download_mode &&
(in_panic || restart_mode == RESTART_DLOAD));
//设置dload
#endif
/* Hard reset the PMIC unless memory contents must be maintained. */
if
(get_dload_mode() || (cmd != NULL && cmd[
0
] !=
''
))
qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);
//设置PIMC为热重启
else
qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
//设置PIMC为硬重启
if
(cmd != NULL) {
if
(!strncmp(cmd, bootloader,
10
)) {
__raw_writel(
0x77665500
, restart_reason);
//写一些东东到IMEM,用于bootloader,recovery等
}
else
if
(!strncmp(cmd, recovery,
8
)) {
__raw_writel(
0x77665502
, restart_reason);
}
else
if
(!strcmp(cmd, rtc)) {
__raw_writel(
0x77665503
, restart_reason);
}
else
if
(!strncmp(cmd, oem-,
4
)) {
unsigned
long
code;
int
ret;
ret = kstrtoul(cmd +
4
,
16
, &code);
if
(!ret)
__raw_writel(
0x6f656d00
| (code &
0xff
),
restart_reason);
}
else
if
(!strncmp(cmd, edl,
3
)) {
enable_emergency_dload_mode();
}
else
{
__raw_writel(
0x77665501
, restart_reason);
}
}
.....
}
do_msm_poweroff()与do_msm_restart()都设置了dload,PMIC,唯一不同的是do_msm_restart()里多了一个__raw_writel的动作,即reason写入IMEM,目的在于重启进入sbl1时判断应该进入那种模式,如我们开发用的bootloader模式,恢复出厂设置的recovery模式等。
- android系统关机流程
- android系统关机流程
- android 关机 流程分析
- android 关机 流程分析
- Android 关机流程
- android 关机 流程分析
- Android 关机流程分析
- android系统关机流程
- android 关机流程分析
- android 关机流程
- android系统关机流程
- android 关机 流程分析
- Android关机流程
- Android关机流程
- android 关机 流程分析
- android 关机 流程分析
- Android poweroff 关机流程
- Android关机流程
- Handler post 和 sendmessage的解析
- 软工之白盒测试的6种逻辑覆盖
- Viewpager自动无限轮播+小圆点
- MongoDB身份验证--命令行模式
- ubuntu 14.04 安装cuda
- Android关机流程
- 学习openCV之读取图像和感兴趣区域融合
- 使用ShareSDK完成第三方(QQ、微信、微博)登录和分享
- 用gSOAP开发Web Service程序
- CodeForces 669B Little Artem and Grasshopper
- iOS 开发调试技巧
- 什么时候使用静态方法、非静态方法
- PHP实现四位数字+字母验证码
- Unresolved compilation problems: