1. 关机流程

Android上层触发关机的入口很多,但最终几乎都是调用ShutdownThread.shutdown来实现。如下是一些常见的调用关机的点:

  • StatusBarManagerService#shutdown, 这个主要是对接SystemUI(StatusBarManager是Android 系统中的一个服务,用于管理状态栏和快速设置等组件)

  • WindowManagerService#shutdown, 以WindowManagerFuncs接口提供给系统其他模块使用,诸如GlobalActions、PhoneWindowManager。

  • PowerManager#shutdown, 以binder服务形式提供给客户端调用,需要持有android.permission.REBOOT权限。

  • 通过action启动ShutdownActivity请求关机重启,需要权限 android.permission.SHUTDOWN

ACTION_REQUEST_SHUTDOWN = “com.android.internal.intent.action.REQUEST_SHUTDOWN”;

1.1 PowerManager#shutdown

mService实际上是PowerManagerService binder服务的bp端, 执行mService.shutdown实际上是向 PMS binder服务发起调用

/**
* Turn off the device.
*
* @param confirm If true, shows a shutdown confirmation dialog.
* @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param wait If true, this call waits for the shutdown to complete and does not return.
*
* @hide
*/
public void shutdown(boolean confirm, String reason, boolean wait) {
try { // 向 PowerManagerService 发起binder调用
mService.shutdown(confirm, reason, wait);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

1.2 PowerManagerService$BinderService#shutdown

上面的调用将会调用以下代码

/**
* Shuts down the device.
*
* @param confirm If true, shows a shutdown confirmation dialog.
* @param wait If true, this call waits for the shutdown to complete and does not return.
*/
@Override // Binder call
public void shutdown(boolean confirm, String reason, boolean wait) {
// 检查执行是否有
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
// 记录 shutdown 事件,会在log中进行打印
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try { // 直接给 PowerManagerService 处理
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}

1.3 ShutdownCheckPoints#recordCheckPoint

ShutdownCheckPoints 类是一个专门用来记录关机重启详细信息,如调用者pid,原因

/** Records the pid of the caller process as a shutdown check point. */
public static void recordCheckPoint(int callerProcessId, @Nullable String reason) {
INSTANCE.recordCheckPointInternal(callerProcessId, reason);
} @VisibleForTesting
void recordCheckPointInternal(int callerProcessId, @Nullable String reason) {
recordCheckPointInternal(callerProcessId == Process.myPid()
? new SystemServerCheckPoint(mInjector, reason)
: new BinderCheckPoint(mInjector, callerProcessId, reason));
// systme log 中打印 shutdown 原因
Slog.v(TAG, "Binder shutdown checkpoint recorded with pid=" + callerProcessId);
}

1.4 ShutdownThread#shutdown

confirm 参数表示是否需要确认,若需要确认会弹出一个对话框。

/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
* is shown.
*
* @param context Context used to display the shutdown progress dialog. This must be a context
* suitable for displaying UI (aka Themable).
* @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false; // 关机或重启标志
mRebootSafeMode = false;
mReason = reason;
shutdownInner(context, confirm);
}

1.4.1 ShutdownThread#shutdownInner

private static void shutdownInner(final Context context, boolean confirm) {
// ShutdownThread is called from many places, so best to verify here that the context passed
// in is themed.
context.assertRuntimeOverlayThemable(); // ensure that only one thread is trying to power down.
// any additional calls are just returned
synchronized (sIsStartedGuard) {
if (sIsStarted) { // 进行中
Log.d(TAG, "Request to shutdown already running, returning.");
return;
}
} // Add checkpoint for this shutdown attempt. The user might still cancel the dialog, but
// this point preserves the system trace of the trigger point of the ShutdownThread.
ShutdownCheckPoints.recordCheckPoint(/* reason= */ null); 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);
}
}

1.4.2 ShutdownThread#beginShutdownSequence

private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
return;
}
sIsStarted = true;
}
// 显示关机对话框
sInstance.mProgressDialog = showShutdownDialog(context);
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); // make sure we never fall asleep again
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;
} // also make sure the screen stays on for better user experience
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);
} // start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start(); // sInstance是ShutdownThread对象 其继承自Thread,开启线程执行关机流程
}

1.4.3 ShutdownThread#run

/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio state if the allotted time has passed.
*/
public void run() {
TimingsTraceLog shutdownTimingLog = newTimingsLog();
shutdownTimingLog.traceBegin("SystemServerShutdown");
metricShutdownStart();
metricStarted(METRIC_SYSTEM_SERVER); // Start dumping check points for this shutdown in a separate thread.
Thread dumpCheckPointsThread = ShutdownCheckPoints.newDumpThread(
new File(CHECK_POINTS_FILE_BASENAME));// 将记录写入/data/system/shutdown-checkpoints/checkpoints
dumpCheckPointsThread.start(); BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
actionDone(); // 结束关机广播处理
}
}; /*
* Write a system property in case the system_server reboots before we
* get to the actual hardware restart. If that happens, we'll retry at
* the beginning of the SystemServer startup.
*/
{
String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
} /*
* If we are rebooting into safe mode, write a system property
* indicating so.
*/
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..."); // First send the high-level shut down 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; // 10s 超时
synchronized (mActionDoneSync) { // 等待关机广播处理完成,上面调用通知actionDone
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 {
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); final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) { // ams 处理shutdown
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");
if (pm != null) { // pms 处理shutdown
pm.shutdown();
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // ShutdownPackageManager
metricEnded(METRIC_PM); // Shutdown 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); // If it's to reboot to install an update and uncrypt hasn't been
// done yet, trigger it now.
uncrypt();
} // Wait for the check points dump thread to finish, or kill it if not finished in time.
shutdownTimingLog.traceBegin("ShutdownCheckPointsDumpWait");
try {
dumpCheckPointsThread.join(MAX_CHECK_POINTS_DUMP_WAIT_TIME);
} catch (InterruptedException ex) { // 等待记录写入完成
}
shutdownTimingLog.traceEnd(); // ShutdownCheckPointsDumpWait shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot, mReason);
// Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason); // 继续执行
}

1.4.4 ShutdownThread#rebootOrShutdown

通过PowerManagerService来实现 shutdown/reboot

1.5 PowerManagerService#lowLevelShutdown

此方法通过设置属性sys.powerctl来通知init处理shutdown

/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
*
* @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
*/
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}

设置属性sys.powerctl值,init的property service将会接受设置的值并进行处理。

1.6 HandlePropertySet

init处理设置属性

// @system/core/init/property_service.cpp
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr,
SocketConnection* socket, std::string* error) {
if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
return ret;
} if (StartsWith(name, "ctl.")) { // 处理 ctl.xxx
return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
} // sys.powerctl is a special property that is used to make the device reboot. We want to log
// any process that sets this property to be able to accurately blame the cause of a shutdown.
if (name == "sys.powerctl") { // 设置的sys.powerctl
std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
std::string process_cmdline;
std::string process_log_string;
if (ReadFileToString(cmdline_path, &process_cmdline)) {
// Since cmdline is null deliminated, .c_str() conveniently gives us just the process
// path.
process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
}
// 打印log
LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
<< process_log_string;
if (!value.empty()) {
DebugRebootLogging();
}
if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
*error = "Userspace reboot is not supported by this device";
return PROP_ERROR_INVALID_VALUE;
}
} // If a process other than init is writing a non-empty value, it means that process is
// requesting that init performs a restorecon operation on the path specified by 'value'.
// We use a thread to do this restorecon operation to prevent holding up init, as it may take
// a long time to complete.
if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
static AsyncRestorecon async_restorecon;
async_restorecon.TriggerRestorecon(value);
return PROP_SUCCESS;
} return PropertySet(name, value, error); // 设置属性
}

1.6.1 PropertyChanged

当设置成功后,会调用PropertyChanged

// @system/core/init/init.cpp
void PropertyChanged(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
// commands to be executed.
if (name == "sys.powerctl") { // 处理sys.powerctl属性变化
trigger_shutdown(value); // 触发关机
} if (property_triggers_enabled) {
ActionManager::GetInstance().QueuePropertyChange(name, value);
WakeMainInitThread();
} prop_waiter_state.CheckAndResetWait(name, value);
}

trigger_shutdown在SecondStageMain中定义,是一个lambda表达式

int SecondStageMain(int argc, char** argv) {
...
trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
...
}

因此接下来调用 ShutdownState#TriggerShutdown

// @system/core/init/init.cpp
void TriggerShutdown(const std::string& command) {
// We can't call HandlePowerctlMessage() directly in this function,
// because it modifies the contents of the action queue, which can cause the action queue
// to get into a bad state if this function is called from a command being executed by the
// action queue. Instead we set this flag and ensure that shutdown happens before the next
// command is run in the main init loop.
auto lock = std::lock_guard{shutdown_command_lock_};
shutdown_command_ = command;
do_shutdown_ = true;
WakeMainInitThread(); // 唤醒主线程处理
}

在主线程的循环中处理 shutdown command

// @system/core/init/init.cpp
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
LOG(INFO) << "Got shutdown_command '" << *shutdown_command
<< "' Calling HandlePowerctlMessage()";
HandlePowerctlMessage(*shutdown_command);
shutdown_state.set_do_shutdown(false);
}

1.6.2 HandlePowerctlMessage

// @system/core/init/reboot.cpp
void HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vector<std::string> cmd_params = Split(command, ",");
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
bool userspace_reboot = false; if (cmd_params[0] == "shutdown") { // 处理关机
cmd = ANDROID_RB_POWEROFF;
if (cmd_params.size() >= 2) {
if (cmd_params[1] == "userrequested") {
// The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
// Run fsck once the file system is remounted in read-only mode.
run_fsck = true;
} else if (cmd_params[1] == "thermal") {
// Turn off sources of heat immediately.
TurnOffBacklight();
// run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
}
}
} else if (cmd_params[0] == "reboot") { // 处理重启
cmd = ANDROID_RB_RESTART2;
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
if (reboot_target == "userspace") {
LOG(INFO) << "Userspace reboot requested";
userspace_reboot = true;
}
// adb reboot fastboot should boot into bootloader for devices not
// supporting logical partitions.
if (reboot_target == "fastboot" &&
!android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
reboot_target = "bootloader";
}
// When rebooting to the bootloader notify the bootloader writing
// also the BCB.
if (reboot_target == "bootloader") {
std::string err;
if (!write_reboot_bootloader(&err)) {
LOG(ERROR) << "reboot-bootloader: Error writing "
"bootloader_message: "
<< err;
}
} else if (reboot_target == "recovery") {
bootloader_message boot = {};
if (std::string err; !read_bootloader_message(&boot, &err)) {
LOG(ERROR) << "Failed to read bootloader message: " << err;
}
// Update the boot command field if it's empty, and preserve
// the other arguments in the bootloader message.
if (!CommandIsPresent(&boot)) {
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
if (std::string err; !write_bootloader_message(boot, &err)) {
LOG(ERROR) << "Failed to set bootloader message: " << err;
return;
}
}
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
reboot_target == "fastboot") {
std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
: reboot_target;
const std::vector<std::string> options = {
"--" + arg,
};
std::string err;
if (!write_bootloader_message(options, &err)) {
LOG(ERROR) << "Failed to set bootloader message: " << err;
return;
}
reboot_target = "recovery";
} // If there are additional parameter, pass them along
for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {
reboot_target += "," + cmd_params[i];
}
}
} else {
command_invalid = true;
}
if (command_invalid) {
LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
return;
} // We do not want to process any messages (queue'ing triggers, shutdown messages, control
// messages, etc) from properties during reboot.
StopSendingMessages(); if (userspace_reboot) {
HandleUserspaceReboot();
return;
} LOG(INFO) << "Clear action queue and start shutdown trigger";
ActionManager::GetInstance().ClearQueue();
// Queue shutdown trigger first
ActionManager::GetInstance().QueueEventTrigger("shutdown");
// Queue built-in shutdown_done
auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
DoReboot(cmd, command, reboot_target, run_fsck); // 关键
return Result<void>{};
};
// 将shutdown封装为<Builtin Action>并添加到队列,之后在主循环被处理,接着DoReboot将被调用
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done"); EnterShutdown();
}

cmd 定义如下

// @system/core/libcutils/include/cutils/android_reboot.h
/* Commands */
#define ANDROID_RB_RESTART 0xDEAD0001 /* deprecated. Use RESTART2. */
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
#define ANDROID_RB_THERMOFF 0xDEAD0004

EnterShutdown 用以清除wait prop和 pending exec flag

static void EnterShutdown() {
LOG(INFO) << "Entering shutdown mode";
shutting_down = true;
// Skip wait for prop if it is in progress
ResetWaitForProp();
// Clear EXEC flag if there is one pending
for (const auto& s : ServiceList::GetInstance()) {
s->UnSetExec();
}
}

1.7 DoReboot

接下来,在shutdown action被处理后,DoReboot被调用

// @system/core/init/reboot.cpp
//* Reboot / shutdown the system.
// cmd ANDROID_RB_* as defined in android_reboot.h
// reason Reason string like "reboot", "shutdown,userrequested"
// reboot_target Reboot target string like "bootloader". Otherwise, it should be an empty string.
// run_fsck Whether to run fsck after umount is done.
//
static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& reboot_target,
bool run_fsck) {
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target; bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF; auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) { // 计算timeout
constexpr unsigned int shutdown_timeout_default = 6;
constexpr unsigned int max_thermal_shutdown_timeout = 3;
auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
shutdown_timeout_default);
if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
shutdown_timeout_final = max_thermal_shutdown_timeout;
}
shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
}
LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms"; sem_t reboot_semaphore;
if (sem_init(&reboot_semaphore, false, 0) == -1) {
// These should never fail, but if they do, skip the graceful reboot and reboot immediately.
LOG(ERROR) << "sem_init() fail and RebootSystem() return!";
RebootSystem(cmd, reboot_target);
} // Start a thread to monitor init shutdown process
LOG(INFO) << "Create reboot monitor thread.";
bool reboot_monitor_run = true;
// 创建 monitor 线程
std::thread reboot_monitor_thread(&RebootMonitorThread, cmd, reboot_target, &reboot_semaphore,
shutdown_timeout, &reboot_monitor_run);
reboot_monitor_thread.detach(); // Start reboot monitor thread
sem_post(&reboot_semaphore); // Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;
std::vector<std::string> reasons = Split(reason, ",");
if (reasons.size() >= 2 && reasons[0] == "reboot" &&
(reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
reasons[1] == "hard" || reasons[1] == "warm")) {
skip = strlen("reboot,");
}
// 写重启原因到属性和文件
// /* Android reboot reason stored in this property */
// #define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
// #define LAST_REBOOT_REASON_FILE "/metadata/bootstat/" LAST_REBOOT_REASON_PROPERTY
PersistRebootReason(reason.c_str() + skip, true); // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
// worry about unmounting it.
if (!IsDataMounted()) { // data没有挂载,直接调用RebootSystem
sync();
RebootSystem(cmd, reboot_target);
abort();
} // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
std::set<std::string> stop_first;
for (const auto& s : ServiceList::GetInstance()) {
if (kDebuggingServices.count(s->name())) {
// keep debugging tools until non critical ones are all gone.
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
if (auto result = s->Start(); !result.ok()) {
LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
<< "': " << result.error();
}
s->SetShutdownCritical();
} else if (s->IsShutdownCritical()) {
// Start shutdown critical service if not started.
if (auto result = s->Start(); !result.ok()) {
LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
<< "': " << result.error();
}
} else {
stop_first.insert(s->name());
}
} // remaining operations (specifically fsck) may take a substantial duration
if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
TurnOffBacklight();
} // 处理关机动画
Service* boot_anim = ServiceList::GetInstance().FindService("bootanim");
Service* surface_flinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (boot_anim != nullptr && surface_flinger != nullptr && surface_flinger->IsRunning()) {
bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false); if (do_shutdown_animation) {
SetProperty("service.bootanim.exit", "0");
SetProperty("service.bootanim.progress", "0");
// Could be in the middle of animation. Stop and start so that it can pick
// up the right mode.
boot_anim->Stop();
} for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count("animation") == 0) {
continue;
} // start all animation classes if stopped.
if (do_shutdown_animation) {
service->Start();
}
service->SetShutdownCritical(); // will not check animation class separately
} if (do_shutdown_animation) {
boot_anim->Start();
surface_flinger->SetShutdownCritical();
boot_anim->SetShutdownCritical();
}
} // optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
if (shutdown_timeout > 0ms) {
StopServicesAndLogViolations(stop_first, shutdown_timeout / 2, true /* SIGTERM */);
}
// Send SIGKILL to ones that didn't terminate cleanly.
StopServicesAndLogViolations(stop_first, 0ms, false /* SIGKILL */);
SubcontextTerminate();
// Reap subcontext pids.
ReapAnyOutstandingChildren(); // 3. send volume abort_fuse and volume shutdown to vold
Service* vold_service = ServiceList::GetInstance().FindService("vold");
if (vold_service != nullptr && vold_service->IsRunning()) {
// Manually abort FUSE connections, since the FUSE daemon is already dead
// at this point, and unmounting it might hang.
CallVdc("volume", "abort_fuse");
CallVdc("volume", "shutdown");
vold_service->Stop();
} else {
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here 停止 logcat
StopServices(kDebuggingServices, 0ms, false /* SIGKILL */);
// 4. sync, try umount, and optionally run fsck for user shutdown
{
Timer sync_timer;
LOG(INFO) << "sync() before umount...";
sync();
LOG(INFO) << "sync() before umount took" << sync_timer;
}
// 5. drop caches and disable zram backing device, if exist
KillZramBackingDevice(); LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t;
// 6. unmount active apexes, otherwise they might prevent clean unmount of /data.
if (auto ret = UnmountAllApexes(); !ret.ok()) {
LOG(ERROR) << ret.error();
}
UmountStat stat =
TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore);
// Follow what linux shutdown is doing: one more sync with little bit delay
{
Timer sync_timer;
LOG(INFO) << "sync() after umount...";
sync();
LOG(INFO) << "sync() after umount took" << sync_timer;
}
if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t); // Send signal to terminate reboot monitor thread.
reboot_monitor_run = false;
sem_post(&reboot_semaphore); // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, reboot_target); /// 执行关机重启
abort();
}

1.8 RebootSystem

// @system/core/init/reboot_utils.cpp
void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
LOG(INFO) << "Reboot ending, jumping to kernel"; if (!IsRebootCapable()) {
// On systems where init does not have the capability of rebooting the
// device, just exit cleanly.
exit(0);
} switch (cmd) {
case ANDROID_RB_POWEROFF: // 关机
reboot(RB_POWER_OFF);
break; case ANDROID_RB_RESTART2: // 重启
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
break; case ANDROID_RB_THERMOFF:
if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);
} else {
reboot(RB_POWER_OFF);
}
break;
}
// In normal case, reboot should not return.
PLOG(ERROR) << "reboot call returned";
abort();
}

接着调用bionic 的 reboot 函数:

// @bionic/libc/bionic/reboot.cpp
#include <unistd.h>
#include <sys/reboot.h> extern "C" int __reboot(int, int, int, void*); int reboot(int mode) {
// 调用 linux reboot 函数
return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, nullptr);
}

1.9 C++层关机入口

在C++代码里面可以直接调用 android_reboot 来实现关机重启

// @system/core/libcutils/include/cutils/android_reboot.h
/* Commands */
#define ANDROID_RB_RESTART 0xDEAD0001 /* deprecated. Use RESTART2. */
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
#define ANDROID_RB_THERMOFF 0xDEAD0004 /* Properties */
#define ANDROID_RB_PROPERTY "sys.powerctl" /* Android reboot reason stored in this property */
#define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
#define LAST_REBOOT_REASON_FILE "/metadata/bootstat/" LAST_REBOOT_REASON_PROPERTY /* Reboot or shutdown the system.
* This call uses ANDROID_RB_PROPERTY to request reboot to init process.
* Due to that, process calling this should have proper selinux permission
* to write to the property or the call will fail.
*/
int android_reboot(unsigned cmd, int flags, const char* arg);

1.9.1 android_reboot

// @system/core/libcutils/android_reboot.cpp
int android_reboot(unsigned cmd, int /*flags*/, const char* arg) {
int ret;
const char* restart_cmd = NULL;
char* prop_value; switch (cmd) {
case ANDROID_RB_RESTART: // deprecated
case ANDROID_RB_RESTART2:
restart_cmd = "reboot";
break;
case ANDROID_RB_POWEROFF:
restart_cmd = "shutdown";
break;
case ANDROID_RB_THERMOFF:
restart_cmd = "shutdown,thermal";
break;
}
if (!restart_cmd) return -1;
if (arg && arg[0]) {
ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
} else {
ret = asprintf(&prop_value, "%s", restart_cmd);
}
if (ret < 0) return -1;
// 设置属性sys.powerctl, 和上层一样都会触发init执行关机
ret = property_set(ANDROID_RB_PROPERTY, prop_value);
free(prop_value);
return ret;
}

1.10 关机流程总结

Java层:

ShutdownThread#shutdown -> PowerManagerService#lowLevelShutdown -> 设置属性"sys.powerctl" -> init处理关机 -> bionic reboot -> linux __reboot

C++层

android_reboot -> 设置属性"sys.powerctl" -> init处理关机 -> bionic reboot -> linux __reboot

2. 重启流程

Android上层重启的入口与关机流程类似,只是调用的方法从shutdown变成了 reboot,也是调用 ShutdownThread.reboot 来实现。如下是一些常见的调用关机的点:

  • StatusBarManagerService#reboot, 这个主要是对接SystemUI

  • WindowManagerService#reboot, 以WindowManagerFuncs接口提供给系统其他模块使用,诸如GlobalActions、PhoneWindowManager。

  • PowerManager#reboot, 以binder服务形式提供给客户端调用,需要持有android.permission.REBOOT权限。通过action启动ShutdownActivity请求关机重启,需要权限 android.permission.SHUTDOWN

  • ACTION_REQUEST_SHUTDOWN = “com.android.internal.intent.action.REQUEST_SHUTDOWN”;

2.1 ShutdownThread#reboot

/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
* is shown.
*
* @param context Context used to display the shutdown progress dialog. This must be a context
* suitable for displaying UI (aka Themable).
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm); // 和关机类似,最终调用rebootOrShutdown
}

2.2 rebootOrShutdown

重启情况是通过PowerManagerService.lowLevelReboot进行重启

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;
} ...
expected return from lowLevelReboot!");
}

2.3 PowerManagerService#lowLevelReboot

/**
* Low-level function to reboot the device. On success, this
* function doesn't return. If more than 20 seconds passes from
* the time a reboot is requested, this method returns.
*
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
*/
public static void lowLevelReboot(String reason) {
if (reason == null) {
reason = "";
} // If the reason is "quiescent", it means that the boot process should proceed
// without turning on the screen/lights.
// The "quiescent" property is sticky, meaning that any number
// of subsequent reboots should honor the property until it is reset.
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)) { // 进入 recovery
reason = "recovery";
} if (sQuiescent) {
// Pass the optional "quiescent" argument to the bootloader to let it know
// that it should not turn the screen/lights on.
reason = reason + ",quiescent";
}
// 设置sys.powerctl
SystemProperties.set("sys.powerctl", "reboot," + reason);
try {
Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}

如同关机流程,设置sys.powerctl然后init会执行重启。

3. 如何分析关机重启问题

了解了上面的流程,分析问题应该不难,查看关键的log即可。下面以关机为例来分析,对于关机的机器来说,通常插上充电器是会进入关机充电状态,有关机充电动画。而某些情况实际是发生了死机,插上充电器没有充电动画,一般需要长按10+s开机。

3.1 查看main log

主要看下ShutdownThread log

01-22 15:54:05.117339  2174  2174 D ShutdownThread: Notifying thread to start shutdown longPressBehavior=1
01-22 15:54:05.181086 2174 25190 I ShutdownThread: Sending shutdown broadcast...
01-22 15:54:06.122875 2174 25190 I ShutdownThread: Shutting down activity manager...
01-22 15:54:06.233849 2174 25190 I ShutdownThread: Shutting down package manager...
01-22 15:54:06.242261 2174 25296 W ShutdownThread: Turning off cellular radios...
01-22 15:54:06.256316 2174 25296 I ShutdownThread: Waiting for Radio...
01-22 15:54:06.558647 2174 25296 I ShutdownThread: Radio turned off.
01-22 15:54:06.558735 2174 25296 I ShutdownThread: Radio shutdown complete.
01-22 15:54:07.118474 2174 25190 I ShutdownThread: Shutdown critical subsyslist is :modem :
01-22 15:54:07.118492 2174 25190 I ShutdownThread: Waiting for a maximum of 10000ms
01-22 15:54:07.608521 2174 25190 I ShutdownThread: Vendor subsystem(s) shutdown successful
01-22 15:54:07.608561 2174 25190 I ShutdownThread: Performing low-level shutdown...

3.2 查看system log

可以查看ShutdownCheckPoints,看看是那个进程发起的,比如这里的 pid=3393 就是 systemui 触发的关机。

01-22 15:54:05.114927  2174 12696 V ShutdownCheckPoints: Binder shutdown checkpoint recorded with pid=3393
01-22 15:54:05.117219 2174 2174 V ShutdownCheckPoints: System server shutdown checkpoint recorded

3.3 查看 sys.boot.reason

结合开机后的开机原因,可以获取更多信息,比如下面的一些原因

// 通常是用户操作
[sys.boot.reason]: [shutdown,userrequested]
// 这种通常是低电导致,可以看下kernel的healthd 查看下电量上报信息
[sys.boot.reason]: [shutdown,battery]

重启关机的原因有很多,如下定义在PowerManager

/// frameworks/base/core/java/android/os/PowerManager.java
/**
* The value to pass as the 'reason' argument to reboot() to reboot into
* recovery mode for tasks other than applying system updates, such as
* doing factory resets.
* <p>
* Requires the {@link android.Manifest.permission#RECOVERY}
* permission (in addition to
* {@link android.Manifest.permission#REBOOT}).
* </p>
* @hide
*/
public static final String REBOOT_RECOVERY = "recovery"; /**
* The value to pass as the 'reason' argument to reboot() to reboot into
* recovery mode for applying system updates.
* <p>
* Requires the {@link android.Manifest.permission#RECOVERY}
* permission (in addition to
* {@link android.Manifest.permission#REBOOT}).
* </p>
* @hide
*/
public static final String REBOOT_RECOVERY_UPDATE = "recovery-update"; /**
* The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
* the device.
* @hide
*/
public static final String REBOOT_REQUESTED_BY_DEVICE_OWNER = "deviceowner"; /**
* The 'reason' value used when rebooting in safe mode
* @hide
*/
public static final String REBOOT_SAFE_MODE = "safemode"; /**
* The 'reason' value used for rebooting userspace.
* @hide
*/
@SystemApi
public static final String REBOOT_USERSPACE = "userspace"; /**
* The 'reason' value used when rebooting the device without turning on the screen.
* @hide
*/
public static final String REBOOT_QUIESCENT = "quiescent"; /**
* The value to pass as the 'reason' argument to android_reboot().
* @hide
*/
public static final String SHUTDOWN_USER_REQUESTED = "userrequested"; /**
* The value to pass as the 'reason' argument to android_reboot() when battery temperature
* is too high.
* @hide
*/
public static final String SHUTDOWN_BATTERY_THERMAL_STATE = "thermal,battery"; /**
* The value to pass as the 'reason' argument to android_reboot() when device temperature
* is too high.
* @hide
*/
public static final String SHUTDOWN_THERMAL_STATE = "thermal"; /**
* The value to pass as the 'reason' argument to android_reboot() when device is running
* critically low on battery.
* @hide
*/
public static final String SHUTDOWN_LOW_BATTERY = "battery";

除了上面的原因,重启原因还包括如下

rescueparty / RescueParty  --- RescueParty机制重启的原因
rollback_staged_install --- crashes回滚机制重启

3.4 healthd 信息

查看kernel log查看healthd的电量信息

// l=0 电量值
// t=25.0 电池温度℃
// chg= 充电状态,为空是没有进行充电
05-19 17:49:59.253565 1200 1200 W healthd : battery l=0 v=7892 t=25.0 h=2 st=3 c=320 fc=13320000 cc=5 chg=

3.4.1 healthd log 打印

/// system/core/healthd/BatteryMonitor.cpp
void BatteryMonitor::logValues(const android::hardware::health::V2_1::HealthInfo& health_info,
const struct healthd_config& healthd_config) {
char dmesgline[256];
size_t len;
const HealthInfo_1_0& props = health_info.legacy.legacy;
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
props.batteryHealth, props.batteryStatus); len = strlen(dmesgline);
if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
props.batteryCurrent);
} if (!healthd_config.batteryFullChargePath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
props.batteryFullCharge);
} if (!healthd_config.batteryCycleCountPath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
props.batteryCycleCount);
}
} else {
len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
} snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
props.chargerWirelessOnline ? "w" : ""); KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
}

3.5 查看 PMIC PON log

而有些情况是看不到上面的log,通常可能是异常关机,可以查看开机后的 kernel 的 PMIC PON log

01-01 08:00:21.958147   418   418 I         : PMIC PON log: Fundamental Reset: PON_PBL_STATUS=XVDD, DVDD
01-01 08:00:21.958160 418 418 I : PMIC PON log: FAULT_REASON2=RESTART_PON
01-01 08:00:21.958212 418 418 I : PMIC PON log: PON Trigger: USB_CHARGER
01-01 08:00:21.958262 418 418 I : PMIC PON log: Reset Trigger: PS_HOLD
01-01 08:00:21.958273 418 418 I : PMIC PON log: Reset Type: HARD_RESET
01-01 08:00:21.958304 418 418 I : PMIC PON log: PON Trigger: KPDPWR_N
01-01 08:00:21.958315 418 418 I : PMIC PON log: PON Trigger: HARD_RESET

3.6 一些常见场景

如下包含一些关机重启的场景的触发点

3.6.1 低电

/// @frameworks/base/services/core/java/com/android/server/BatteryService.java
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
if (shouldShutdownLocked()) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mActivityManagerInternal.isSystemReady()) {
// 使用intent启动ShutdownActivity来执行关机
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
intent.putExtra(Intent.EXTRA_REASON,
PowerManager.SHUTDOWN_LOW_BATTERY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
}
});
}
}

3.6.1 高温

/// @frameworks/base/services/core/java/com/android/server/BatteryService.java
private void shutdownIfOverTempLocked() {
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) { // 温度超标关机, 默认临界68度
mHandler.post(new Runnable() {
@Override
public void run() {
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
intent.putExtra(Intent.EXTRA_REASON,
PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
}
});
}
}

3.6.2 Thermal

/// @frameworks/base/services/core/java/com/android/server/power/ThermalManagerService.java
private void shutdownIfNeeded(Temperature temperature) {
if (temperature.getStatus() != Temperature.THROTTLING_SHUTDOWN) {
return;
}
final PowerManager powerManager = getContext().getSystemService(PowerManager.class);
switch (temperature.getType()) {
case Temperature.TYPE_CPU:
// Fall through
case Temperature.TYPE_GPU:
// Fall through
case Temperature.TYPE_NPU:
// Fall through
case Temperature.TYPE_SKIN: // 设置硬件高温
powerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
break;
case Temperature.TYPE_BATTERY: // 电池高温
powerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
break;
}
}

3.6.3 status bar关机重启

这个通常是从systemui发起

/// frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
/**
* Allows the status bar to shutdown the device.
*/
@Override
public void shutdown() {
enforceStatusBarService();
String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
// ShutdownThread displays UI, so give it a UI context.
mHandler.post(() ->
ShutdownThread.shutdown(getUiContext(), reason, false));
} finally {
Binder.restoreCallingIdentity(identity);
}
} /**
* Allows the status bar to reboot the device.
*/
@Override
public void reboot(boolean safeMode) {
enforceStatusBarService();
String reason = safeMode
? PowerManager.REBOOT_SAFE_MODE
: PowerManager.SHUTDOWN_USER_REQUESTED;
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
mHandler.post(() -> {
// ShutdownThread displays UI, so give it a UI context.
if (safeMode) {
ShutdownThread.rebootSafeMode(getUiContext(), true);
} else {
ShutdownThread.reboot(getUiContext(), reason, false);
}
});
} finally {
Binder.restoreCallingIdentity(identity);
}
}

3.6.4 Rollback重启

@WorkerThread
private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
BroadcastReceiver listener, @Nullable VersionedPackage logPackage) {
assertInWorkerThread();
PackageInstaller packageInstaller =
mContext.getPackageManager().getPackageInstaller();
List<RollbackInfo> recentRollbacks =
rollbackManager.getRecentlyCommittedRollbacks();
for (int i = 0; i < recentRollbacks.size(); i++) {
RollbackInfo recentRollback = recentRollbacks.get(i);
int sessionId = recentRollback.getCommittedSessionId();
if ((rollbackId == recentRollback.getRollbackId())
&& (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
PackageInstaller.SessionInfo sessionInfo =
packageInstaller.getSessionInfo(sessionId);
if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) {
mContext.unregisterReceiver(listener);
saveStagedRollbackId(rollbackId, logPackage);
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
"");
} else if (sessionInfo.isStagedSessionFailed()
&& markStagedSessionHandled(rollbackId)) {
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
"");
mContext.unregisterReceiver(listener);
}
}
} // Wait for all pending staged sessions to get handled before rebooting.
if (isPendingStagedSessionsEmpty()) {
mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
}
}

还有更多场景就不一一列出了。

Android 12 关机重启流程的更多相关文章

  1. 【转】android 电池(二):android关机充电流程、充电画面显示

    关键词:android 电池关机充电 androidboot.mode charger关机充电 充电画面显示 平台信息:内核:linux2.6/linux3.0系统:android/android4. ...

  2. android 电池(二):android关机充电流程、充电画面显示【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下a ...

  3. Android系统关机或重启的几种实现方式

    前阵子工作上遇到一些关于Android系统关机或重启的系统修改,于是,做了一些尝试,也搜集了一下资料,现在整理一下,做一些总结,方便学习或者日后工作的需要. 默认的SDK并没有提供应用开发者直接的An ...

  4. 让Android程序获得系统的权限,实现关机重启,静默安装等功能

    引用:http://www.cnblogs.com/welenwho/archive/2012/05/10/2494984.html android想要获得系统权限有几种途径,一种就是你的程序固化的系 ...

  5. Android实训案例(二)——Android下的CMD命令之关机重启以及重启recovery

    Android实训案例(二)--Android下的CMD命令之关机重启以及重启recovery Android刚兴起的时候,着实让一些小众软件火了一把,切水果,Tom猫,吹裙子就是其中的代表,当然还有 ...

  6. Android 12(S) 图形显示系统 - createSurface的流程(五)

    题外话 刚刚开始着笔写作这篇文章时,正好看电视在采访一位92岁的考古学家,在他的日记中有这样一句话,写在这里与君共勉"不要等待幸运的降临,要去努力的掌握知识".如此朴实的一句话,此 ...

  7. Android 12(S) 图形显示系统 - BufferQueue的工作流程(八)

    题外话 最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从"愚昧之巅"掉到"绝望之谷"了,哈哈哈 邓宁-克鲁格效应 一.前言 前面的文章中已经 ...

  8. Android 12(S) 图形显示系统 - BufferQueue的工作流程(九)

    题外话 Covid-19疫情的强烈反弹,小区里检测出了无症状感染者.小区封闭管理,我也不得不居家办公了.既然这么大把的时间可以光明正大的宅家里,自然要好好利用,八个字 == 努力工作,好好学习 一.前 ...

  9. Android 12(S) 图形显示系统 - BufferQueue的工作流程(十)

    题外话 疫情隔离在家,周末还在努力学习的我  ..... 一.前言 上一篇文章中,有基本讲清楚Producer一端的处理逻辑,最后也留下了一个疑问: Consumer是什么时候来消费数据的?他是自己主 ...

  10. Android 12(S) 图像显示系统 - HWC HAL 初始化与调用流程

    必读: Android 12(S) 图像显示系统 - 开篇 接口定义 源码位置:/hardware/interfaces/graphics/composer/ 在源码目录下可以看到4个版本的HIDL ...

随机推荐

  1. 简单聊聊WebDAV

    1.什么是WebDAV? WebDAV是一种基于HTTP协议的扩展,旨在提供在Web服务器上进行文件管理的标准化解决方案.它允许用户通过网络对远程主机上的文件进行读写.编辑和删除操作.与传统的HTTP ...

  2. 【Vue2】Vue-Cli使用

    1.需要NodeJS环境支持,此处省略NodeJS安装 2.使用NPM命令安装CLI包 vue-cli是npm.上的一个全局包,使用npm install 命令,即可方便的把它安装到自己的电脑上: n ...

  3. 【Mybatis】Bonus01 笔记资料

    对原生JDBC程序的问题总结 public void jdbc() { // 声明Connection对象 Connection con; // 驱动程序名 String driver = " ...

  4. conda报错、anconda报错:requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

    anconda报错,报错信息: requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0) 不能使用c ...

  5. batch normalization的multi-GPU版本该怎么实现? 【Tensorflow 分布式PS/Worker模式下异步更新的情况】

    最近由于实验室有了个AI计算平台,于是研究了些分布式和单机多GPU的深度学习代码,于是遇到了下面的讨论: https://www.zhihu.com/question/59321480/answer/ ...

  6. 标准DQN在测试算法性能时为什么要将探索概率epsilon设置为0.05呢,而不是使用其他探索概率的epsilon-greedy策略或者直接使用greedy探索策略呢?

    标准dqn的策略网络参数更新所采用的规则为Q-learning中的更新规则,总所周知的是Q-learning是异策略算法,异策略算法就是行为策略和评估策略(更新所得策略)是不同的. 更新规则: q-l ...

  7. ubuntu18.04环境下如何为 vs code 实现ftp功能

    如前文所述  https://www.cnblogs.com/devilmaycry812839668/p/14797739.html , 在vs code 自身环境下的ftp功能插件难以使用,而在W ...

  8. maven项目打包时排除依赖包

    1.背景 为了快速上传jar包到服务器,很多时候我们需要把依赖包单独独立出来,避免每次修改都传依赖包 2.实现方式 maven的pom文件,没有独立依赖包时配置如下: <build> &l ...

  9. Java基础之数值类型之间的转换

    经常需要将一种数值类型转换为另一种数值类型.下图 给出了数值类型之间的合法 转换. 在图中有 6 个实心箭头,表示无信息丢失的转换:有 3 个虚箭头, 表示可能有精度 损失的转换. 例如,123 45 ...

  10. 对话框通过EndDialog返回值传值回父窗体

    1. 调用对话(模式调用) MyDialog dlg(this); INT_PTR nRet=dlg.DoModal(); //这里接收模态对话框传出来的指针 if(nRet==IDCANCEL) / ...