我参考的项目是高通sdm710芯片android版本为8.1.0:
关机源码详解
当我们长按电源键时,按键消息会传递给PhoneWindowManager中的interceptKeyBeforeQueueing()函数处理。该函数代码如下:
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
.......
// Handle special keys.
switch (keyCode) {
.......
case KeyEvent.KEYCODE_POWER: {//处理按键事件为电源键的情况
// Any activity on the power button stops the accessibility shortcut
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);//处理按下电源键的方法
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
}
}
我们查看interceptPowerKeyDown()方法:
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
// Cancel multi-press detection timeout.
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
}
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();//处理按键截图功能
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telecomManager.silenceRinger();//电话铃声停止功能
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telecomManager.endCall();//挂断电话功能
}
}
GestureLauncherService gestureService = LocalServices.getService(
GestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);//发送长按电源消息
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);//发送长按电源消息
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}
我们查看“MSG_POWER_LONG_PRESS”的消息处理代码:
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
......
case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
showGlobalActionsInternal();//处理消息MSG_DISPATCH_SHOW_GLOBAL_ACTIONS
break;
......
case MSG_POWER_LONG_PRESS:
powerLongPress();//处理消息MSG_POWER_LONG_PRESS
break;
我们再查看方法powerLongPress:
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();//获取行为类型
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS://行为类型为1,执行此分支
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
showGlobalActionsInternal();//查看此方法
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}
我们再查看getResolvedLongPressOnPowerBehavior方法:
private int getResolvedLongPressOnPowerBehavior() {
if (FactoryTest.isLongPressOnPowerOffEnabled()) {
return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
}
return mLongPressOnPowerBehavior;
}
我们不是工厂测试,所以我们不是返回LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM,mLongPressOnPowerBehavior的值是PhoneWindowManager::init()中赋值的。代码如下:
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
......
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);//获取mLongPressOnPowerBehavior值
}
我们可以查看到配置文件frameworks\base\core\res\res\values\config.xml:
<!-- Control the behavior when the user long presses the power button.
0 - Nothing
1 - Global actions menu
2 - Power off (with confirmation)
3 - Power off (without confirmation)
-->
<integer name="config_longPressOnPowerBehavior">1</integer>
可以看到,mLongPressOnPowerBehavior=1,再由消息值的定义,
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
那么我们可以知道方法powerLongPress中是LONG_PRESS_POWER_GLOBAL_ACTIONS :
case LONG_PRESS_POWER_GLOBAL_ACTIONS://行为类型为1,执行此分支
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
showGlobalActionsInternal();//查看此方法
break;
我们再查看方法showGlobalActionsInternal:
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);//发送关闭系统窗口的消息
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());//显示对话框
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
// poke the wake lock so they have some time to see the dialog.
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}
我们再查看showDialog方法:
frameworks\base\services\core\java\com\android\server\policy\GlobalActions.java
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = deviceProvisioned;
mShowing = true;
if (mStatusBarConnected) {
mStatusBarInternal.showGlobalActions();
mHandler.postDelayed(mShowTimeout, 5000);
} else {
// SysUI isn't alive, show legacy menu.
ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);//调用对象mLegacyGlobalActions的showDialog方法
}
}
我们再查看类LegacyGlobalActions人showDialog方法:
frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
/**
* Show the global actions dialog (creating if necessary)
* @param keyguardShowing True if keyguard is showing
*/
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
handleShow();//调用handleShow方法
}
}
handleShow方法如下:
private void handleShow() {
awakenIfNecessary();
mDialog = createDialog();//创建对话框
prepareDialog();
// If we only have 1 item and it's a simple press action, just do this action.
if (mAdapter.getCount() == 1
&& mAdapter.getItem(0) instanceof SinglePressAction
&& !(mAdapter.getItem(0) instanceof LongPressAction)) {
((SinglePressAction) mAdapter.getItem(0)).onPress();
} else {
if (mDialog != null) {
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("LegacyGlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();//显示对话框
mDialog.getWindow().getDecorView().setSystemUiVisibility(
View.STATUS_BAR_DISABLE_EXPAND);
}
}
}
createDialog方法如下:
/**
* Create the global actions dialog.
* @return A new dialog.
*/
private GlobalActionsDialog createDialog() {
// Simple toggle style if there's no vibrator, otherwise use a tri-state
if (!mHasVibrator) {
mSilentModeAction = new SilentModeToggleAction();
} else {
mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
}
mAirplaneModeOn = new ToggleAction(
R.drawable.ic_lock_airplane_mode,
R.drawable.ic_lock_airplane_mode_off,
R.string.global_actions_toggle_airplane_mode,
R.string.global_actions_airplane_mode_on_status,
R.string.global_actions_airplane_mode_off_status) {
@Override
void onToggle(boolean on) {
if (mHasTelephony && Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
mIsWaitingForEcmExit = true;
// Launch ECM exit dialog
Intent ecmDialogIntent =
new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(ecmDialogIntent);
} else {
changeAirplaneModeSystemSetting(on);
}
}
@Override
protected void changeStateFromPress(boolean buttonOn) {
if (!mHasTelephony) return;
// In ECM mode airplane state cannot be changed
if (!(Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
}
}
@Override
public boolean showDuringKeyguard() {
return true;
}
@Override
public boolean showBeforeProvisioning() {
return false;
}
};
onAirplaneModeChanged();
mItems = new ArrayList<Action>();//根据不同的按键,显示不同的内容
String[] defaultActions = mContext.getResources().getStringArray(
com.android.internal.R.array.config_globalActionsList);
ArraySet<String> addedKeys = new ArraySet<String>();
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
// If we already have added this, don't add it again.
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
mItems.add(new PowerAction());
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
mItems.add(new BugReportAction());
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
if (mShowSilentToggle) {
mItems.add(mSilentModeAction);
}
} else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
addUsersToMenu(mItems);
}
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
mItems.add(getSettingsAction());
} else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
mItems.add(getLockdownAction());
} else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
mItems.add(getVoiceAssistAction());
} else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
mItems.add(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
mItems.add(new RestartAction());
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(getEmergencyAction());
}
mAdapter = new MyAdapter();//适配器,用以显示内容
AlertParams params = new AlertParams(mContext);
params.mAdapter = mAdapter;
params.mOnClickListener = this;
params.mForceInverseBackground = true;
GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);//要显示的关机对话框
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.getListView().setItemsCanFocus(true);
dialog.getListView().setLongClickable(true);
dialog.getListView().setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
long id) {
final Action action = mAdapter.getItem(position);
if (action instanceof LongPressAction) {
return ((LongPressAction) action).onLongPress();//响应长按操作
}
return false;
}
});
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
dialog.setOnDismissListener(this);
return dialog;
}
由于关机对话框中的每个列表项对应一个Action,从creatDialog()函数中可知,关机对应的Action为PowerAction()。
frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
代码如下:
private final class PowerAction extends SinglePressAction implements LongPressAction {
private PowerAction() {
super(com.android.internal.R.drawable.ic_lock_power_off,
R.string.global_action_power_off);
}
@Override
public boolean onLongPress() {//长按
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.rebootSafeMode(true);//重启
return true;
}
return false;
}
@Override
public boolean showDuringKeyguard() {
return true;
}
@Override
public boolean showBeforeProvisioning() {
return true;
}
@Override
public void onPress() {//按下关机
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */);//调用关机
}
}
当单击对话框中的"关机"时,会执行WindowManagerFuncs对象mWindowManagerFuncs的成员函数shutdown()。那mWindowManagerFuncs从哪来的呢?是创建GlobalActino对象时候通过构造函数的参数传进来的。
/**
* @param context everything needs a context :(
*/
public LegacyGlobalActions(Context context, WindowManagerFuncs windowManagerFuncs,
Runnable onDismiss) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
其实WindowManagerService类是实现接口WindowManagerFuncs :
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
那么mWindowManagerFuncs的成员函数shutdown()实现自然是WindowManagerService::shutdown(),代码如下:
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
/**
* 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);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);//关机
} finally {
Binder.restoreCallingIdentity(ident);
}
}
shutdown方法启动关机:
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
shutdownOrRebootInternal方法调用ShutdownThread.shutdown:
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.shutdown调用了shutdownInner方法:
public static void shutdown(final Context context, String reason, boolean confirm) {
......
shutdownInner(context, confirm);
}
shutdownInner方法显示关机确认对话框,点击关机调用方法beginShutdownSequence:
private static void shutdownInner(final Context context, boolean confirm) {
......
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);//开始关机流程
}
}
beginShutdownSequence方法使cpu不再睡眠,使屏幕显示为亮,启动初始化关机线程:
private static void beginShutdownSequence(Context context) {
......
// make sure we never fall asleep again//处理CPU睡眠锁
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;
}
}
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start();//启动关机线程
}
再执行run方法:
public void run() {
......
/*
* 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);//设置系统属性SHUTDOWN_ACTION_PROPERTY
}
/*
* If we are rebooting into safe mode, write a system property
* indicating so.
*/
if (mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");//设置系统属性REBOOT_SAFEMODE_PROPERTY
}
......
// 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_INCLUDE_BACKGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
......
final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);//关闭ActivityManager
} catch (RemoteException e) {
}
}
......
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();//关闭PackageManagerService
}
......
// Shutdown radios.
shutdownTimingLog.traceBegin("ShutdownRadios");
metricStarted(METRIC_RADIOS);
shutdownRadios(MAX_RADIO_WAIT_TIME);//关闭radios
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
......
// Shutdown StorageManagerService to ensure media is in a safe state
IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
actionDone();//关闭StorageManagerService
}
};
// Set initial variables and time out time.
mActionDone = false;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
final IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.checkService("mount"));
if (storageManager != null) {
storageManager.shutdown(observer);//关闭storageManager
} else {
Log.w(TAG, "StorageManagerService unavailable for shutdown");
}
} catch (Exception e) {
Log.e(TAG, "Exception during StorageManagerService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "StorageManager shutdown wait timed out");
break;
} else if (mRebootHasProgressBar) {
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.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
} catch (InterruptedException e) {
}
}
}
......
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();//调用uncrypt方法
}
......
saveMetrics(mReboot);
rebootOrShutdown(mContext, mReboot, mReason);//调用rebootOrShutdown方法
}
调用rebootOrShutdown():
/**
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
* or {@link #shutdown(Context, String, boolean)} instead.
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
* @param reason reason for reboot/shutdown
*/
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方法:
/**
* 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值
}
我们再查看文件system\core\init\init.cpp,发现当系统属性sys.powerctl值改变时,发送事件property_changed:
void property_changed(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") {
// Despite the above comment, we can't call HandlePowerctlMessage() 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.
// TODO: once property service is removed from init, this will never happen from a builtin,
// but rather from a callback from the property service socket, in which case this hack can
// go away.
shutdown_command = value;//关机命令
do_shutdown = true;//关机
}
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
if (waiting_for_prop) {
if (wait_prop_name == name && wait_prop_value == value) {
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
ResetWaitForProp();
}
}
}
我们再查看main方法:
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {//处理关机命令
shutting_down = true;
}
}
我们再查看文件system\core\init\reboot.cpp的HandlePowerctlMessage方法:
bool HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vector<std::string> cmd_params = android::base::Split(command, ",");
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
if (cmd_params.size() > 3) {
command_invalid = true;
} else if (cmd_params[0] == "shutdown") {//关机
cmd = ANDROID_RB_POWEROFF;//关机命令
if (cmd_params.size() == 2 && 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;
}
static 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);//调用reboot方法
break;
在文件system\core\libcutils\android_reboot.c中的android_reboot方法关机:
int android_reboot(int cmd, int flags __unused, 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";
至此,基本上已经结束.
优化关机patch:
(1)https://source.codeaurora.org/quic/la/device/qcom/common/commit/?id=91f5a62a950f59559eccf476e43f1072e8b6ef0a
(2)https://source.codeaurora.org/quic/la/platform/frameworks/base/commit/services?id=4299cef5ebd66c7e2646c68f9a5838733806d776
参考资料:
(1)[Android5.1]关机工作流程
https://blog.csdn.net/u010753159/article/details/51366366