PowerManager的shutdown方法用于请求设备关机,代码如下:
//frameworks/base/core/java/android/os/PowerManager.java
public final class PowerManager {
public void shutdown(boolean confirm, String reason, boolean wait) {
try {
mService.shutdown(confirm, reason, wait);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
调用mService(IPowerManager)的shutdown方法,IPowerManager是一个接口,由PowerManagerService的内部类BinderService实现:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
final class BinderService extends IPowerManager.Stub {
public void shutdown(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
}
调用PowerManagerService 的shutdownOrRebootInternal方法:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
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();
}
if (mHandler == null || !mSystemReady) {
if (RescueParty.isAttemptingFactoryReset()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
// No check point from ShutdownCheckPoints will be dumped at this state.
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
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);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(UiThread.getHandler(), runnable);
msg.setAsynchronous(true);
UiThread.getHandler().sendMessage(msg);
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
if (wait) {
synchronized (runnable) {
while (true) {
try {
runnable.wait();
} catch (InterruptedException e) {
}
}
}
}
}
}
上面方法更加不同的haltMode模式调用不同的方法:
1、调用ShutdownThread的rebootSafeMode方法。
2、调用ShutdownThread的reboot方法。
3、调用ShutdownThread的shutdown方法。
下面分别进行分析:
ShutdownThread rebootSafeMode
调用ShutdownThread的rebootSafeMode方法:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
public static void rebootSafeMode(final Context context, boolean confirm) {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
return;
}
mReboot = true;
mRebootSafeMode = true;
mRebootHasProgressBar = false;
mReason = null;
shutdownInner(context, confirm);
}
}
ShutdownThread reboot
调用ShutdownThread的reboot方法:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
}
上述三个方法都调用了ShutdownThread的shutdownInner方法:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
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);
}
}
}
调用ShutdownThread的beginShutdownSequence方法:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
private static final ShutdownThread sInstance = new ShutdownThread();
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();
}
}
ShutdownThread run
调用sInstance(ShutdownThread)的start方法,之后会运行到ShutdownThread的run:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
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));
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;
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 {
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) {
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 PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
if (pm != null) {
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);
}
}
调用ShutdownThread的rebootOrShutdown方法:
//frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public final class ShutdownThread extends Thread {
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) {
// vibrate before shutting down
// 关机前震动
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.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
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);
}
}
调用PowerManagerService的lowLevelShutdown方法:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
}
调用SystemProperties的set方法,SystemProperties是一个用于访问和修改Android系统属性的工具类。系统属性是一些键值对,用于存储和传递系统相关的配置信息。通过SystemProperties类,开发者可以获取和设置这些系统属性:
//frameworks/base/core/java/android/os/SystemProperties.java
public class SystemProperties {
public static void set(@NonNull String key, @Nullable String val) {
if (val != null && !key.startsWith("ro.") && val.getBytes(StandardCharsets.UTF_8).length
> PROP_VALUE_MAX) {
throw new IllegalArgumentException("value of system property '" + key
+ "' is longer than " + PROP_VALUE_MAX + " bytes: " + val);
}
if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
}
调用native_set方法,native_set是Native方法,在android_os_SystemPropecties.cpp中定义:
//frameworks/base/core/jni/android_os_SystemPropecties.cpp
void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
jstring valJ)
{
ScopedUtfChars key(env, keyJ);
if (!key.c_str()) {
return;
}
std::optional<ScopedUtfChars> value;
if (valJ != nullptr) {
value.emplace(env, valJ);
if (!value->c_str()) {
return;
}
}
bool success;
#if defined(__BIONIC__)
success = !__system_property_set(key.c_str(), value ? value->c_str() : "");
#else
success = android::base::SetProperty(key.c_str(), value ? value->c_str() : "");
#endif
if (!success) {
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property (check logcat for reason)");
}
}