您的位置:首页 > 移动开发 > Android开发

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]

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模式等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: