android L 关机流程分析
2016-01-25 20:27
489 查看
frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
ShutdownThread.java文件
stop playing music,因为后面可能要playing shutdown music.
代码如下:
?
show system dialog to indicate phone is shutting down,如果没有关机动画的话,要show一个关机提示出来。
代码如下:
synchronized (mEnableAnimatingSync) {
if(!mEnableAnimating) {
//sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);
} else {
if (mShutOffAnimation) {
Log.e(TAG, "mIBootAnim.isCustBootAnim() is true");
bootanimCust();
} else {
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);
/* To fix video+UI+blur flick issue */
pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
pd.show();
}
sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime);
}
}
?
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该保存数据赶紧的,我要关机了
代码如下:
/// M: 2012-05-20 ALPS00286063 @{
mContext.sendBroadcast(new Intent("android.intent.action.ACTION_PRE_SHUTDOWN"));
/// @} 2012-05-20
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.putExtra("_mode", mShutdownFlow);
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上有所区别
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
[ActivityManagerService.java]
shutdown package manager,保存app使用时间到 disk里,这是android L新增的功能。
代码如下:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
[PackageManagerService.java]
?
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");
if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
Log.d(TAG, "change shutdown flow from ipo to normal: MountService");
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
?
走完上层关机流程,下面就要执行关机动作了。
代码如下
/**
* 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);
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
// power off auto test, don't modify
Log.i(TAG, "Performing low-level shutdown...");
//unmout data/cache partitions while performing shutdown
PowerManagerService.lowLevelShutdown();
/* sleep for a long time, prevent start another service */
try {
Thread.currentThread().sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");
}
}
?
从代码上看始终会走到lowLevelShutdown(),但如果是重启就不会,lowLevelReboot()就停止了。
lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,其实都只是设置一个属性:SystemProperties.set(sys.powerctl, xxx);
正是这个动作触发关机流程往下走,这涉及到init进程的4大功能,请参考我的另一篇文章Android的init进程
sys.powerctl属性触发开关在init.rc定义
system/core/rootdir/init.rc
我们来解读这句话,on property:sys.powerctl=*表示当属性sys.powerctl设置为任何值是都会跑到这里,触发动作是powerctl ${sys.powerctl},这个动作的意思是调用powerctl指令,并把sys.powerctl的值传给它。powerctl指令在init进程会执行。
从下面的表可知,powerctl对应的操作是do_powerctl
[system/core/init/keywords.h]
代码如下:
[system/core/init/builtins.c]
?
它调用android_reboot()函数,实现如下:
[system/core/libcutils/android_reboot.c]
?
从这里看出它的主要工作:
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]
?
调用了__reboot,它在汇编实现 如下:
[bionic/libc/arch-arm/syscalls/__reboot.S]
__NR_reboot对应的内核入口在哪里?
如下:
[bionic/libc/kernel/uapi/asm-generic/unistd.h]
?
它在内核入口如下:
注:bionic/libc/kernel/uapi/asm-generic/unistd.h与kernel/include/uapi/asm-generic/unistd.h是对应的,方便以后代码追踪
[kernel/include/uapi/asm-generic/unistd.h]
__NR_reboot 映射到 sys_reboot
grep 下sys_reboot 找不到,其实在这里
用SYSCALL_DEFINE定义
[kernel/kernel/sys.c]
除了前面不同,都调用了device_shutdown()函数,关闭外设。
machine_power_off() machine_resestart()函数实现
?
pm_power_offf() arm_pm_restart()都是一个函数指针
赋值如下:
[kernel/drivers/power/reset/msm-poweroff.c]
高通平台的关机代码与之前有所不同,现在文件msm-poweroff.c以前是restart.c。
do_msm_poweroff()与do_msm_restart()实现如下:
msm_restart_prepare()实现
do_msm_poweroff()与do_msm_restart()都设置了dload,PMIC,唯一不同的是do_msm_restart()里多了一个__raw_writel的动作,即reason写入IMEM,目的在于重启进入sbl1时判断应该进入那种模式,如我们开发用的bootloader模式,恢复出厂设置的recovery模式等。
ShutdownThread.java文件
stop playing music,因为后面可能要playing shutdown music.
代码如下:
show system dialog to indicate phone is shutting down,如果没有关机动画的话,要show一个关机提示出来。
代码如下:
synchronized (mEnableAnimatingSync) {
if(!mEnableAnimating) {
//sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);
} else {
if (mShutOffAnimation) {
Log.e(TAG, "mIBootAnim.isCustBootAnim() is true");
bootanimCust();
} else {
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);
/* To fix video+UI+blur flick issue */
pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
pd.show();
}
sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime);
}
}
?
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该保存数据赶紧的,我要关机了
代码如下:
/// M: 2012-05-20 ALPS00286063 @{
mContext.sendBroadcast(new Intent("android.intent.action.ACTION_PRE_SHUTDOWN"));
/// @} 2012-05-20
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.putExtra("_mode", mShutdownFlow);
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上有所区别
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
[ActivityManagerService.java]
shutdown package manager,保存app使用时间到 disk里,这是android L新增的功能。
代码如下:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
[PackageManagerService.java]
?
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");
if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
Log.d(TAG, "change shutdown flow from ipo to normal: MountService");
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
?
走完上层关机流程,下面就要执行关机动作了。
代码如下
/**
* 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);
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
// power off auto test, don't modify
Log.i(TAG, "Performing low-level shutdown...");
//unmout data/cache partitions while performing shutdown
PowerManagerService.lowLevelShutdown();
/* sleep for a long time, prevent start another service */
try {
Thread.currentThread().sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");
}
}
?
从代码上看始终会走到lowLevelShutdown(),但如果是重启就不会,lowLevelReboot()就停止了。
lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,其实都只是设置一个属性:SystemProperties.set(sys.powerctl, xxx);
正是这个动作触发关机流程往下走,这涉及到init进程的4大功能,请参考我的另一篇文章Android的init进程
sys.powerctl属性触发开关在init.rc定义
system/core/rootdir/init.rc
我们来解读这句话,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)
代码如下:
[system/core/init/builtins.c]
?
它调用android_reboot()函数,实现如下:
[system/core/libcutils/android_reboot.c]
?
从这里看出它的主要工作:
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]
?
调用了__reboot,它在汇编实现 如下:
[bionic/libc/arch-arm/syscalls/__reboot.S]
__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]
__NR_reboot 映射到 sys_reboot
grep 下sys_reboot 找不到,其实在这里
用SYSCALL_DEFINE定义
[kernel/kernel/sys.c]
除了前面不同,都调用了device_shutdown()函数,关闭外设。
machine_power_off() machine_resestart()函数实现
?
pm_power_offf() arm_pm_restart()都是一个函数指针
赋值如下:
[kernel/drivers/power/reset/msm-poweroff.c]
高通平台的关机代码与之前有所不同,现在文件msm-poweroff.c以前是restart.c。
do_msm_poweroff()与do_msm_restart()实现如下:
msm_restart_prepare()实现
do_msm_poweroff()与do_msm_restart()都设置了dload,PMIC,唯一不同的是do_msm_restart()里多了一个__raw_writel的动作,即reason写入IMEM,目的在于重启进入sbl1时判断应该进入那种模式,如我们开发用的bootloader模式,恢复出厂设置的recovery模式等。
相关文章推荐
- ImageView 相关
- Android之WebRTC实现
- Android使用学习之画图(Canvas,Paint)与手势感应及其应用(乒乓球小游戏)
- Android基础知识(1)
- Android TV Input Framework(TIF)--3 显示Tv Input内容
- Android之WebRTC介绍(二)
- Android Settings.System的使用
- Android开发随笔
- Android源码之Matrix
- Android Framework层Power键关机流程
- Android Branch and master source code merge(patch)
- 这些年正Android - 序言
- 这些年正Android - 序言
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- android lint的使用
- Android 判断ListView是否在滚动到底部
- Android 设计模式之(三)观察者,适配器,桥接,组合模式