framework/base/services/core/java/com/android/server/power/PowerManagerServer.java framework/base/services/core/java/com/android/server/power/ShutdownThread.java
一、概述
重启动作从按键触发中断,linux kernel层给Android framework层返回按键事件进入 framework层,再从 framework层到kernel层执行kernel层关机任务。当然还有非按键触发,比如系统异常导致重启,或者直接调用PM的reboot()方法重启。
这里就先从PowerManager说起。
二、关机流程
2.1 PM.reboot
[-> PowerManager.java]
public void reboot(String reason) { try { //【见小节2.2】 mService.reboot(false, reason, true); } catch (RemoteException e) { } }
2.2 BinderService.reboot
[-> PowerManagerService.java]
private final class BinderService extends IPowerManager.Stub { public void reboot(boolean confirm, String reason, boolean wait) { //权限检查 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); if (PowerManager.REBOOT_RECOVERY.equals(reason)) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); } final long ident = Binder.clearCallingIdentity(); try { //【见小节2.3】 shutdownOrRebootInternal(false, confirm, reason, wait); } finally { Binder.restoreCallingIdentity(ident); } } }
此时参数为shutdownOrRebootInternal(false, false, reason, true);
shutdown=false:代表重启;
confirm=false:代表直接重启,无需弹出询问提示框;
wait=true:代表阻塞等待重启操作完成。
2.3 PMS.shutdownOrRebootInternal
[-> PowerManagerService.java]
private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm, final String reason, boolean wait) { ... Runnable runnable = new Runnable() { @Override public void run() { synchronized (this) { if (shutdown) { ShutdownThread.shutdown(mContext, reason, confirm); } else { //重启则进入该分支【见小节2.4】 ShutdownThread.reboot(mContext, reason, confirm); } } } }; // ShutdownThread必须运行在一个展现UI的looper Message msg = Message.obtain(mHandler, runnable); msg.setAsynchronous(true); mHandler.sendMessage(msg); if (wait) { //等待ShutdownThread执行完毕 synchronized (runnable) { while (true) { try { runnable.wait(); } catch (InterruptedException e) { } } } } }
2.4 ShutdownThread.reboot
[-> ShutdownThread.java]
public static void reboot(final Context context, String reason, boolean confirm) { mReboot = true; mRebootSafeMode = false; mRebootUpdate = false; mReason = reason; //【见小节2.5】 shutdownInner(context, confirm); }
mReboot为true则代表重启操作,值为false则代表关机操作。
2.5 shutdownInner
[-> ShutdownThread.java]
static void shutdownInner(final Context context, boolean confirm) { //确保只有唯一的线程执行shutdown/reboot操作 synchronized (sIsStartedGuard) { if (sIsStarted) { return; } } final int longPressBehavior = context.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); final int resourceId = mRebootSafeMode ? com.android.internal.R.string.reboot_safemode_confirm : (longPressBehavior == 2 ? com.android.internal.R.string.shutdown_confirm_question : com.android.internal.R.string.shutdown_confirm); Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior); if (confirm) { //这里是走弹出关机/重启提示框 ... } else { //本次confirm=false进入该分支【见小节2.6】 beginShutdownSequence(context); } }
2.6 beginShutdownSequence
[-> ShutdownThread.java]
private static void beginShutdownSequence(Context context) { synchronized (sIsStartedGuard) { if (sIsStarted) { return; //shutdown操作正在执行,则直接返回 } sIsStarted = true; } //创建进度显示对话框 ProgressDialog pd = new ProgressDialog(context); //当重启原因为"recovery" if (PowerManager.REBOOT_RECOVERY.equals(mReason)) { mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists(); if (mRebootUpdate) { pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title)); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_prepare)); pd.setMax(100); pd.setProgressNumberFormat(null); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setProgress(0); pd.setIndeterminate(false); } else { pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title)); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_reset_message)); pd.setIndeterminate(true); } } else { //重启/关机则进入该分支 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(); sInstance.mProgressDialog = pd; sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); //确保系统不会进入休眠状态 sInstance.mCpuWakeLock = null; try { sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); sInstance.mCpuWakeLock.setReferenceCounted(false); sInstance.mCpuWakeLock.acquire(); } catch (SecurityException e) { sInstance.mCpuWakeLock = null; } //当处理亮屏状态,则获取亮屏锁,提供用户体验 sInstance.mScreenWakeLock = null; if (sInstance.mPowerManager.isScreenOn()) { try { sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); sInstance.mScreenWakeLock.setReferenceCounted(false); sInstance.mScreenWakeLock.acquire(); } catch (SecurityException e) { sInstance.mScreenWakeLock = null; } } sInstance.mHandler = new Handler() {}; //启动线程来执行shutdown初始化【见小节2.7】 sInstance.start(); }
此处ProgressDialog
根据不同reboot reason会不同UI框:
重启到recovery模式,并安装更新
Condition:mReason == REBOOT_RECOVERY and mRebootUpdate == True
检查/cache/recovery/uncrypt_file文件存在,则mRebootUpdate为True
UI: 进度条(progress bar)
重启到recovery,用于工厂重置模式
Condition: mReason == REBOOT_RECOVERY and mRebootUpdate == False
UI: 仅显示spinning circle
常规重启/关机
Condition: Otherwise
UI: 仅显示spinning circle
2.7 ShutdownThread.run
[-> ShutdownThread.java]
public final class ShutdownThread extends Thread { public void run() { BroadcastReceiver br = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { actionDone(); } }; String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : ""); //设置"sys.shutdown.requested"属性值 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason); if (mRebootSafeMode) { //如果需要重启进入安全模式,则设置"persist.sys.safemode"=1 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); } //1. 发送关机广播 mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null); //其中MAX_BROADCAST_TIME=10s final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; synchronized (mActionDoneSync) { while (!mActionDone) { long delay = endTime - SystemClock.elapsedRealtime(); if (delay <= 0) { break; //关机广播超时 } else if (mRebootUpdate) { int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 * BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME); sInstance.setRebootProgress(status, null); } try { //最长等待时间为500ms mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC)); } catch (InterruptedException e) { } } } if (mRebootUpdate) { sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } //2. 关闭AMS final IActivityManager am = ActivityManagerNative.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); } catch (RemoteException e) { } } if (mRebootUpdate) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } //3. 关闭PMS final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); } if (mRebootUpdate) { sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null); } //4. 关闭radios. shutdownRadios(MAX_RADIO_WAIT_TIME); if (mRebootUpdate) { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } //5. 关闭MountService IMountShutdownObserver observer = new IMountShutdownObserver.Stub() { public void onShutDownComplete(int statusCode) throws RemoteException { actionDone(); } }; mActionDone = false; //其中MAX_SHUTDOWN_WAIT_TIME=20s 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); } } catch (Exception e) { Log.e(TAG, "Exception during MountService shutdown", e); } while (!mActionDone) { long delay = endShutTime - SystemClock.elapsedRealtime(); if (delay <= 0) { break; // Mount观察者广播超时 } else if (mRebootUpdate) { int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 * (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) / MAX_SHUTDOWN_WAIT_TIME); status += RADIO_STOP_PERCENT; sInstance.setRebootProgress(status, null); } try { //当收到mActionDoneSync.notifyAll(),则继续往下执行程序 mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC)); } catch (InterruptedException e) { } } } ... //【2.8】 rebootOrShutdown(mContext, mReboot, mReason); } }
设置”sys.shutdown.requested”,记录下mReboot
和mReason
。如果是进入安全模式,则”persist.sys.safemode=1”。
接下来主要关闭一些系统服务:
发送关机广播
关闭AMS
关闭PMS
关闭radios
关闭MountService
之后就需要进入重启/关机流程。
2.7.1 AMS.shutdown
通过AMP.shutdown,通过binder调用到AMS.shutdown.
public boolean shutdown(int timeout) { //权限检测 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " + android.Manifest.permission.SHUTDOWN); } boolean timedout = false; synchronized(this) { mShuttingDown = true; //禁止WMS继续处理Event updateEventDispatchingLocked(); timedout = mStackSupervisor.shutdownLocked(timeout); } mAppOpsService.shutdown(); if (mUsageStatsService != null) { mUsageStatsService.prepareShutdown(); } mBatteryStatsService.shutdown(); synchronized (this) { mProcessStats.shutdownLocked(); notifyTaskPersisterLocked(null, true); } return timedout; }
此处timeout为MAX_BROADCAST_TIME=10s
2.7.2 PMS.shutdown
public void shutdown() { mPackageUsage.write(true); }
此处mPackageUsage数据类型是PMS的内部类PackageUsage。
private class PackageUsage { void write(boolean force) { if (force) { writeInternal(); return; } ... } }
对于force=true,接下来调用writeInternal方法。
private class PackageUsage { private void writeInternal() { synchronized (mPackages) { synchronized (mFileLock) { //file是指/data/system/package-usage.list AtomicFile file = getFile(); FileOutputStream f = null; try { //将原来的文件记录到package-usage.list.bak f = file.startWrite(); BufferedOutputStream out = new BufferedOutputStream(f); FileUtils.setPermissions(file.getBaseFile().getPath(), 0640, SYSTEM_UID, PACKAGE_INFO_GID); StringBuilder sb = new StringBuilder(); for (PackageParser.Package pkg : mPackages.values()) { if (pkg.mLastPackageUsageTimeInMills == 0) { continue; } sb.setLength(0); sb.append(pkg.packageName); sb.append(' '); sb.append((long)pkg.mLastPackageUsageTimeInMills); sb.append('\n'); out.write(sb.toString().getBytes(StandardCharsets.US_ASCII)); } out.flush(); //将文件内容同步到磁盘,并删除.bak文件 file.finishWrite(f); } catch (IOException e) { if (f != null) { file.failWrite(f); } Log.e(TAG, "Failed to write package usage times", e); } } } mLastWritten.set(SystemClock.elapsedRealtime()); } }
/data/system/package-usage.list文件中每一行记录一条package及其上次使用时间(单位ms)。
由于IO操作的过程中,写入文件并非立刻就会真正意义上写入物理磁盘,以及在写入文件的过程中还可能中断或者出错等原因的考虑,采用的策略是先将老的文件package-usage.list,重命为增加后缀package-usage.list.bak;然后再往package-usage.list文件写入新的数据,数据写完之后再执行sync操作,将内存数据彻底写入物理磁盘,此时便可以安全地删除原来的package-usage.list.bak文件。
2.7.3 ST.shutdownRadios
[-> ShutdownThread.java]
private void shutdownRadios(final int timeout) { final long endTime = SystemClock.elapsedRealtime() + timeout; Thread t = new Thread() { public void run() { boolean nfcOff; boolean bluetoothOff; boolean radioOff; final INfcAdapter nfc = INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc")); final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); final IBluetoothManager bluetooth = IBluetoothManager.Stub.asInterface(ServiceManager.checkService( BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE)); nfcOff = nfc == null || nfc.getState() == NfcAdapter.STATE_OFF; if (!nfcOff) { nfc.disable(false);//关闭NFC } bluetoothOff = bluetooth == null || !bluetooth.isEnabled(); if (!bluetoothOff) { bluetooth.disable(false); //关闭Bluetooth } radioOff = phone == null || !phone.needMobileRadioShutdown(); if (!radioOff) { phone.shutdownMobileRadios(); //关闭cellular radios } ... //等待NFC, Bluetooth, Radio long delay = endTime - SystemClock.elapsedRealtime(); while (delay > 0) { ... if (radioOff && bluetoothOff && nfcOff) { Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete."); break; } //每间隔500ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时才会退出循环 SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); delay = endTime - SystemClock.elapsedRealtime(); } } }; t.start(); try { t.join(timeout); } catch (InterruptedException ex) { } }
创建新的线程来处理NFC, Radio and Bluetooth这些射频相关的模块的shutdown过程。每间隔500ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时(MAX_RADIO_WAIT_TIME=12s)才会退出循环。
2.7.4 MS.shutdown
[-> MountService.java]
public void shutdown(final IMountShutdownObserver observer) { enforcePermission(android.Manifest.permission.SHUTDOWN); //向名为“MountService”的线程发送H_SHUTDOWN消息 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget(); }
“MountService”线程收到消息后进入handleMessage出来相应消息
class MountServiceHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case H_SHUTDOWN: { final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj; boolean success = false; try { //向vold发送shutdown命令 success = mConnector.execute("volume", "shutdown").isClassOk(); } catch (NativeDaemonConnectorException ignored) { } if (obs != null) { try { //回调方法,告知关闭工作已完成 obs.onShutDownComplete(success ? 0 : -1); } catch (RemoteException ignored) { } } break; } ... } } }
observer的回调方法onShutDownComplete(),会调用actionDone(),该方法通知mActionDoneSync已完成
void actionDone() { synchronized (mActionDoneSync) { mActionDone = true; mActionDoneSync.notifyAll(); } }
调用mActionDoneSync.notifyAll()之后,那么便可以继续往下执行rebootOrShutdown方法。
2.8 rebootOrShutdown
[-> ShutdownThread.java]
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) { if (reboot) { Log.i(TAG, "Rebooting, reason: " + reason); //【见小节2.9】 PowerManagerService.lowLevelReboot(reason); Log.e(TAG, "Reboot failed, will attempt shutdown instead"); reason = null; } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) { ... } // Shutdown power Log.i(TAG, "Performing low-level shutdown..."); PowerManagerService.lowLevelShutdown(reason); }
对于重启原因,logcat会直接输出”Rebooting, reason: “,如果重启失败,则会输出“Reboot failed”,如果无法重启,则会尝试直接关机。
2.9 PMS.lowLevelReboot
public static void lowLevelReboot(String reason) { if (reason == null) { reason = ""; } if (reason.equals(PowerManager.REBOOT_RECOVERY)) { SystemProperties.set("ctl.start", "pre-recovery"); } else { SystemProperties.set("sys.powerctl", "reboot," + reason); } try { Thread.sleep(20 * 1000L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Slog.wtf(TAG, "Unexpected return from lowLevelReboot!"); }
当reboot原因是“recovery”,则设置属性
ctl.start=pre-recovery
;当其他情况,则设置属性”sys.powerctl=reboot,[reason]”。
到此,framework层面的重启就流程基本介绍完了,那么接下来就要进入属性服务,即设置sys.powerctl=reboot,
。
三、总结
先用一句话总结,从最开始的PM.reboot(),经过层层调用,最终重启的核心方法等价于调用SystemProperties.set(“sys.powerctl”, “reboot,” + reason); 也就意味着调用下面命令,也能重启手机:
adb shell setprop sys.powerctl reboot
本文还未结束,还需要进一步上面命令的执行流程,如何进入native,如何进入kernel来完成重启的,以及PM.reboot如何触发的。。。
共同学习,写下你的评论
评论加载中...
作者其他优质文章