一、基本概念
重启一般分为是通过按键触发和非按键触发
- 按键触发
是通过按键触发中断,linux kernel层给Android framework层返回按键事件,然后进入到framework层,再从framework层进入kernel层执行关机任务 - 非按键触发
系统异常导致重启,或直接调用PowerManger的reboot()方法重启
二、关机流程(Framework层)
在PowerManager的文档中给出了关机/重启的方法 reboot,描述很简单就是重启设备,并且重启成功,将没有返回值。相应的需要打开Manifest.permission.REBOOT权限。方法也只有一个参数reason代表特定的重启模式,例如recovery又或者为null。
也不拐弯抹角,直接从PowerManager开始看
PowerManger.reboot
[frameworks/base/core/java/android/os/PowerManager.java]
@RequiresPermission(permission.REBOOT)
public void reboot(@Nullable String reason) {
if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {
throw new UnsupportedOperationException(
"Attempted userspace reboot on a device that doesn't support it");
}
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
-
mService
为IPowerManger
的binder接口服务 - 通过binder调到PowerMangerService的
reboot
函数
PowerManagerService
[frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java]
@Override // Binder call
public void reboot(boolean confirm, @Nullable String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
if (PowerManager.REBOOT_RECOVERY.equals(reason)
|| PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- 通过调用
shutdownOrRebootInternal
来实现关机或者重启 - 其中shutdownOrRebootInterna的四个参数分别为 HALT_MODE_REBOOT, confirm, reason, wait
- HALT_MODE_REBOOT=1 代表重启
- confirm=false 代表直接重启,不需要提示对话框
- wait=false 代表阻塞等待重启操作
shutdownOrRebootInternal
[frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java]
private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
@Nullable final String reason, boolean wait) {
if (PowerManager.REBOOT_USERSPACE.equals(reason)) {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
throw new UnsupportedOperationException(
"Attempted userspace reboot on a device that doesn't support it");
}
UserspaceRebootLogger.noteUserspaceRebootWasRequested();
}
//判断是否PM.Handler初始化和判断系统是否启动成功
if (mHandler == null || !mSystemReady) {
if (RescueParty.isAttemptingFactoryReset()) {
//如果陷入底层重启的循环,并且RescueParty正在恢复出厂设置
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
//根据HALT的类型来执行不同的操作
synchronized (this) {
if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
ShutdownThread.rebootSafeMode(getUiContext(), confirm);
} else if (haltMode == HALT_MODE_REBOOT) {
//重启流程
ShutdownThread.reboot(getUiContext(), reason, confirm);
} else {
//关机流程
ShutdownThread.shutdown(getUiContext(), reason, confirm);
}
}
}
};
// 处理关机的线程必须运行在一个有UI界面上的looper
Message msg = Message.obtain(UiThread.getHandler(), runnable);
msg.setAsynchronous(true);
UiThread.getHandler().sendMessage(msg);
//因为reboot没有返回值,因此只能阻塞等待shutdownThread完成
if (wait) {
synchronized (runnable) {
while (true) {
try {
runnable.wait();
} catch (InterruptedException e) {
}
}
}
}
}
- 通过
PowerManager.isRebootingUserspaceSupportedImpl
检查设备是否支持重新启用用户空间 - 判断PM.Handle是否初始化和系统是否启动
- 根据HAL的不同类型执行相应的操作
- 将shutdownThread运行在UI界面的Looper上
- 等待shutdownThread完成
ShutdownThread.root
[frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java ]
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
- 这个方法的说明就是 需要重启且不用开启安全模式,不用显示进度条。重启参数为传递下来的reson。shutdownInner的confirm为是否需要显示确认对话框,因为是通过reboot重启的,所以这里为false。
shutdownInner
private static void shutdownInner(final Context context, boolean confirm) {
//因为ShutdownThread在很多地方调用,所以就先检查一下传入context
context.assertRuntimeOverlayThemable();
//确保只有一个线程来试图关闭电源,其他的额外的调用均会被返回
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Request to shutdown already running, returning.");
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) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
sConfirmDialog = new AlertDialog.Builder(context)
.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off)
.setMessage(resourceId)
.setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
beginShutdownSequence(context);
}
})
.setNegativeButton(com.android.internal.R.string.no, null)
.create();
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
} else {
beginShutdownSequence(context);
}
}
- 主要还是通过Confirm来判断是否需要确认对话框,如果为真则通过
AlertDialog
创建一个对话框,之后通过setPositiveButton
为对话框设置确定按钮的点击事件。通过setNegativeButton
来设置取消按钮的点击事件。 - 不论是Confirm是否为真,都调用
beginShutdownSequence
beginShutdownSequence
[frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java]
private static void beginShutdownSequence(Context context) {
//同上,还是确保在只有一个线程进行操作
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
return;
}
sIsStarted = true;
}
//通过showShutdownDialog根据context创建对话框
sInstance.mProgressDialog = showShutdownDialog(context);
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) {
Log.w(TAG, "No permission to acquire wake lock", 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) {
Log.w(TAG, "No permission to acquire wake lock", e);
sInstance.mScreenWakeLock = null;
}
}
if (SecurityLog.isLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
}
// 启动关机流程
sInstance.mHandler = new Handler() {
};
sInstance.start();
}
showShutdownDialog
[frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java]
private static ProgressDialog showShutdownDialog(Context context) {
//创建系统对话框来表示设备正在重启/关机
ProgressDialog pd = new ProgressDialog(context);
//如果重启原因是 "recovery-update"或者"recovery-update,quiescent"
if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
&& !(RecoverySystem.BLOCK_MAP_FILE.exists());
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
if (mRebootHasProgressBar) {
pd.setMax(100);
pd.setProgress(0);
pd.setIndeterminate(false);
pd.setProgressNumberFormat(null);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_prepare));
} else {
if (showSysuiReboot()) {
return null;
}
pd.setIndeterminate(true);
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_reboot));
}
} else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
if (RescueParty.isAttemptingFactoryReset()) {
//实际上在这里我们并没有恢复出厂设置,而是生成一个对话框来询问用户是否重置
//给他们一个相对友好的消息。
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);
} 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 {
//正常重启、关机进这个分支
if (showSysuiReboot()) {
return null;
}
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();
return pd;
}
此处 ProgressDialog()
会根据不同的重启原因显示不同的UI界面
- 重启到recovery模式,并安装更新
- Condition: mReason startswith REBOOT_RECOVERY_UPDATE
- 检查/cache/recovery/uncrypt_file文件是否存在,存在,mRebootHasProgressBar == True
- UI:显示进度条
- 重启到recovery模式,并恢复出厂设置
- Condition:mReason == REBOOT_RECOVERY
- UI:不显示进度条,只显示spinning circle
- 正常关机重启
- Condition:Otherwise
- UI:不显示进度条,只显示spinning circle
ShutdownThread.run
public void run() {
TimingsTraceLog shutdownTimingLog = newTimingsLog();
shutdownTimingLog.traceBegin("SystemServerShutdown");
metricShutdownStart();
metricStarted(METRIC_SYSTEM_SERVER);
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// 接收到该广播,则唤醒wait()操作
actionDone();
}
};
//设置属性"sys.shutdown.requested"的值为reason
{
String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
//如果需要重启进入安全模式,则设置"persist.sys.safemode"=1
if (mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
}
shutdownTimingLog.traceBegin("DumpPreRebootInfo");
try {
Slog.i(TAG, "Logging pre-reboot information...");
PreRebootLogger.log(mContext);
} catch (Exception e) {
Slog.e(TAG, "Failed to log pre-reboot information", e);
}
shutdownTimingLog.traceEnd(); // DumpPreRebootInfo
metricStarted(METRIC_SEND_BROADCAST);
shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Log.i(TAG, "Sending shutdown broadcast...");
//首先发送关机广播
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
//MAX_BROADCAST_TIME=10S
synchronized (mActionDoneSync) {
//循环等待
while (!mActionDone) {
long delay = endTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
//超时退出
Log.w(TAG, "Shutdown broadcast timed out");
break;
} else if (mRebootHasProgressBar) {
int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
sInstance.setRebootProgress(status, null);
}
try {
//等待500s
mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
} catch (InterruptedException e) {
}
}
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
metricEnded(METRIC_SEND_BROADCAST);
Log.i(TAG, "Shutting down activity manager...");
shutdownTimingLog.traceBegin("ShutdownActivityManager");
metricStarted(METRIC_AM);
//关闭AMS
final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd();// ShutdownActivityManager
metricEnded(METRIC_AM);
Log.i(TAG, "Shutting down package manager...");
shutdownTimingLog.traceBegin("ShutdownPackageManager");
metricStarted(METRIC_PM);
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
//关闭PMS
if (pm != null) {
pm.shutdown();
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // ShutdownPackageManager
metricEnded(METRIC_PM);
// 关闭 radios.
shutdownTimingLog.traceBegin("ShutdownRadios");
metricStarted(METRIC_RADIOS);
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // ShutdownRadios
metricEnded(METRIC_RADIOS);
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
//如果需要安装升级且没有触发过uncrypt方法,则立即触发
uncrypt();
}
shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot, mReason);
// Remaining work will be done by init, including vold shutdown
//其余的剩下工作交给init进程完成
rebootOrShutdown(mContext, mReboot, mReason);
}
AMS.shutdown 关闭AMS
[frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java]
public boolean shutdown(int timeout) {
//权限检查 检查
if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.SHUTDOWN);
}
final boolean timedout = mAtmInternal.shuttingDown(mBooted, timeout);
mAppOpsService.shutdown();
if (mUsageStatsService != null) {
mUsageStatsService.prepareShutdown();
}
mBatteryStatsService.shutdown();
synchronized (this) {
mProcessStats.shutdownLocked();
}
return timedout;
}
shuttingDown
[frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java]
public boolean shuttingDown(boolean booted, int timeout) {
synchronized (mGlobalLock) {
mShuttingDown = true;
mRootActivityContainer.prepareForShutdown();
//禁止WMS处理event
updateEventDispatchingLocked(booted);
//将最近任务写入磁盘,等待开机挂起
notifyTaskPersisterLocked(null, true);
//调用ASS处理shutdown
return mStackSupervisor.shutdownLocked(timeout);
}
}
PMS.shutdown 关闭PMS
[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
public void shutdown() {
mPackageUsage.writeNow(mPackages);
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
PackageWatchdog.getInstance(mContext).writeNow();
// 将没有存盘的的限制配置进行存盘操作
synchronized (mPackages) {
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
mSettings.writePackageRestrictionsLPr(userId);
}
mDirtyUsers.clear();
}
}
}
shutdownRadios
[frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java]
private void shutdownRadios(final int timeout) {
//如果radio被截断,关闭它可能会阻塞,所以选用另一个线程来处理
final long endTime = SystemClock.elapsedRealtime() + timeout;
final boolean[] done = new boolean[1];
Thread t = new Thread() {
public void run() {
TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
boolean radioOff;
TelephonyManager telephonyManager = mContext.getSystemService(
TelephonyManager.class);
radioOff = telephonyManager == null
|| !telephonyManager.isAnyRadioPoweredOn();
if (!radioOff) {
Log.w(TAG, "Turning off cellular radios...");
metricStarted(METRIC_RADIO);
telephonyManager.shutdownAllRadios(); //关闭所有radio
}
Log.i(TAG, "Waiting for Radio...");
//等待 NFC Bluetooth radio
long delay = endTime - SystemClock.elapsedRealtime();
while (delay > 0) {
if (mRebootHasProgressBar) {
int status = (int)((timeout - delay) * 1.0 *
(RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
status += PACKAGE_MANAGER_STOP_PERCENT;
sInstance.setRebootProgress(status, null);
}
if (!radioOff) {
radioOff = !telephonyManager.isAnyRadioPoweredOn();
if (radioOff) {
Log.i(TAG, "Radio turned off.");
metricEnded(METRIC_RADIO);
shutdownTimingsTraceLog
.logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
}
}
if (radioOff) {
Log.i(TAG, "Radio shutdown complete.");
done[0] = true;
break;
}
//每间隔100ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时才会退出循环
SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
delay = endTime - SystemClock.elapsedRealtime();
}
}
};
t.start();
try {
t.join(timeout);
} catch (InterruptedException ex) {
}
if (!done[0]) {
Log.w(TAG, "Timed out waiting for Radio shutdown.");
}
}
rebootOrShutdown
[frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java]
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, "Reboot failed, will attempt shutdown instead");
reason = null;
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
//关机前先震动
Vibrator vibrator = new SystemVibrator(context);
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
} catch (Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
//振动失败不应中断关机。 只需要记录下log。
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// 震动器是异步的,我们只需要等待以避免过早的关闭
try {
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch (InterruptedException unused) {
}
}
// 关机方法
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);
}
- reboot 为true则重启为false则关机
- 对于重启原因 logcat会直接输出"Rebooting, reason: "
- 如果重启失败,输出Reboot failed, will attempt shutdown instead(重启失败,尝试关机)
SHUTDOWN_VIBRATE_MS
表示关机前震动的时间为500ms
lowLevelReboot
public static void lowLevelReboot(String reason) {
if (reason == null) {
reason = "";
}
if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
sQuiescent = true;
reason = "";
} else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
sQuiescent = true;
reason = reason.substring(0,
reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
}
if (reason.equals(PowerManager.REBOOT_RECOVERY)
|| reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
reason = "recovery";
}
if (sQuiescent) {
reason = reason + ",quiescent";
}
SystemProperties.set("sys.powerctl", "reboot," + reason);
try {
Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
lowLevelShutdown
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
//这里其实相当于在命令行输入 adb shell setprop sys.powerctl reboot
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
- 至此framework层的重启流程就结束了,接下来就是设置 sys.powerctl =root 然后进入native层
- 其实最核心重启方法等价于调用
SystemProperties.set("sys.powerctl", "shutdown," + reason)
也就是说
在命令行输入adb shell setprop sys.powerctl reboot
也是可以完成关机操作
进入Native层