Power键灭屏流程是从PhoneWindowManager监听Power键开始的,PowerManager负责调用PMS下的GoToSleep方法灭屏,Notifier负责发灭屏广播,WinDowManagerPolicy负责锁屏,其时序图如
以按Power键关机流程为例子分析一下流程:
Power键的key值响应在PhoneWindowManager的interceptKeyBeforeQueueing中接收Keycode值做相应的处理(亮灭屏过程中Power down执行wakeup,up执行goToSleep)
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
...
// 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);
}
...
...
}
当检测到Power键被down之后,检测screenshot chord,检测有电话铃声会置静音等操作,
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
...
...
// 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;
}
}
}
}
}
根据interactive标志位检测是否处于活跃状态,如果是且检测到是长按Power键行为,则通过Handler发送
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
...
case MSG_POWER_LONG_PRESS:
powerLongPress();
break;
....
}
}
}
在powerLongPress中
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS://显示系统弹框
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;
}
}
这LONG_PRESS_POWER_GLOBAL_ACTIONS中performHapticFeedbackLw主要是用来获取震动强度showGlobalActionsInternal用来显示系统关机的Dialog
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);//先关闭系统的dialog
if (mGlobalActions == null) {
//创建GlobalActions
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
//showDialog
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\packages\SystemUI\plugin\src\com\android\systemui\plugins\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);
}
}
在showGlobalActions中
frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@Override
public void showGlobalActions(GlobalActionsManager manager) {
if (mGlobalActions == null) {
//创建GlobalActionsDialog
mGlobalActions = new GlobalActionsDialog(mContext, manager);
}
//显示Dislog
mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
mDeviceProvisionedController.isDeviceProvisioned());
}
GlobalActionsDialog
/**
* Helper to show the global actions dialog. Each item is an {@link Action} that
* may show depending on whether the keyguard is showing, and whether the device
* is provisioned.
*/
class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
....
....
public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs) {
...
...
// receive broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
...
...
}
...
...
/**
* 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();
}
}
...
...
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 {
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("ActionsDialog");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mWindowManagerFuncs.onGlobalActionsShown();
}
}
...
...
...
/**
* Create the global actions dialog.
*
* @return A new dialog.
*/
private ActionsDialog createDialog() {
....
.... mItems = new ArrayList<Action>();
String[] defaultActions = mContext.getResources().getStringArray(
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_RESTART.equals(actionKey)) {
mItems.add(new RestartAction());// 添加重启图标和对应事件
}
....
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
...
...
ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.setKeyguardShowing(mKeyguardShowing);
dialog.setOnDismissListener(this);
return dialog;
}
在关机模式中一个是长按diaog重启操作mWindowManagerFuncs.reboot(true);一个是短按mWindowManagerFuncs.shutdown();关机操作
frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
private final class PowerAction extends SinglePressAction implements LongPressAction {
private PowerAction() {
super(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.reboot(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();
}
}
另外RestartAction中重启操作
private final class RestartAction extends SinglePressAction implements LongPressAction {
private RestartAction() {
super(R.drawable.ic_restart, R.string.global_action_restart);
}
@Override
public boolean onLongPress() {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.reboot(true);
return true;
}
return false;
}
@Override
public boolean showDuringKeyguard() {
return true;
}
@Override
public boolean showBeforeProvisioning() {
return true;
}
@Override
public void onPress() {
mWindowManagerFuncs.reboot(false);
}
}
其中的mWindowManagerFuncs来自于
private final GlobalActionsManager mWindowManagerFuncs;
@ProvidesInterface(action = GlobalActions.ACTION, version = GlobalActions.VERSION)
@DependsOn(target = GlobalActionsManager.class)
public interface GlobalActions extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS";
int VERSION = 1;
void showGlobalActions(GlobalActionsManager manager);
default void showShutdownUi(boolean isReboot, String reason) {
}
@ProvidesInterface(version = GlobalActionsManager.VERSION)
public interface GlobalActionsManager {
int VERSION = 1;
void onGlobalActionsShown();
void onGlobalActionsHidden();
void shutdown();
void reboot(boolean safeMode);
}
}
该接口在
frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
...
...
private IStatusBarService mBarService;
@Override
public void start() {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
...
}
...
...
@Override
public void shutdown() {
try {
mBarService.shutdown();
} catch (RemoteException e) {
}
}
@Override
public void reboot(boolean safeMode) {
try {
mBarService.reboot(safeMode);
} catch (RemoteException e) {
}
}
}
而IStatusBarService通过binder的远程实现就是StatusBarManagerService ,而StatusBarManagerService 是在SystemServer中创建的
/**
* A note on locking: We rely on the fact that calls onto mBar are oneway or
* if they are local, that they just enqueue messages to not deadlock.
*/
public class StatusBarManagerService extends IStatusBarService.Stub {
...
...
...
/**
* Allows the status bar to shutdown the device.
*/
@Override
public void shutdown() {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
// ShutdownThread displays UI, so give it a UI context.
mHandler.post(() ->
ShutdownThread.shutdown(getUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, false));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
...
/**
* Allows the status bar to reboot the device.
*/
@Override
public void reboot(boolean safeMode) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
// ShutdownThread displays UI, so give it a UI context.
if (safeMode) {
ShutdownThread.rebootSafeMode(getUiContext(), true);
} else {
ShutdownThread.reboot(getUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, false);
}
});
} finally {
Binder.restoreCallingIdentity(identity);
}
}
reboot和shutdown的具体操作是在ShutdownThread 中完成,看一下ShutdownThread的具体实现
frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
private static AlertDialog sConfirmDialog;
public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;//不是重启
mReason = reason;
shutdownInner(context, confirm);
}
// 具体执行shutdownInner
private static void shutdownInner(final Context context, boolean confirm) {
....
beginShutdownSequence(context);
....
}
///
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);
}
....
....
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
...
这两个后面调用也都是shutdownInner,confirm来确认是否需要再创建关机dialog
在beginShutdownSequence中通过添加PARTIAL_WAKE_LOCK锁防止手机进入休眠状态
private static void beginShutdownSequence(Context context) {
...
...
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);
} catch (SecurityException e) {
Log.w(TAG, "No permission to acquire wake lock", e);
sInstance.mCpuWakeLock = null;
}
...
...
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start();
...
...
}
线程运行,在里面发送关机广播,关闭ActivityManagerService,PackageManagerService,MountService等服务最后执行
01-01 01:33:24.844759 587 3946 I ShutdownThread: Shutting down activity manager...
01-01 01:33:25.318104 587 3946 I ShutdownThread: Shutting down package manager...
01-01 01:33:25.368304 587 4099 W ShutdownThread: Turning off cellular radios...
01-01 01:33:25.490202 587 4099 I ShutdownThread: Waiting for NFC, Bluetooth and Radio...
01-01 01:33:25.994807 949 1154 V PhoneInterfaceManager: [PhoneIntfMgr] 2 Phones are shutdown.
01-01 01:33:25.995463 587 4099 I ShutdownThread: Radio turned off.
01-01 01:33:25.995914 587 4099 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
01-01 01:33:25.995914 587 4099 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
01-01 01:33:25.999106 587 3946 I ShutdownThread: Shutting down StorageManagerService
rebootOrShutdown(mContext, mReboot, mReason);
mShutdownSeqFinish为MTK客制化的MTKShutdownThread中执行客制化动画的包括
关机动画线程延时
shutdownAnimationService
//Turn backlight off
关闭背光灯
setBacklightOff();执行PowerMangerService中的goToSleep
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
*/
public void run() {
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");
}
Log.i(TAG, "Sending shutdown broadcast...");
//发送关机广播
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);
} catch (RemoteException e) {
}
}
....
///M: added for Shutdown Enhancement@{
mShutdownSeqFinish(mContext);
/// @}
....
rebootOrShutdown(mContext, mReboot, mReason);
}
看一下ActivityManagerService中shutdown所执行的操作
@Override
public boolean shutdown(int timeout) {
...
boolean timedout = false;
synchronized(this) {
mShuttingDown = true;
mStackSupervisor.prepareForShutdownLocked();
//
updateEventDispatchingLocked();
timedout = mStackSupervisor.shutdownLocked(timeout);
}
mAppOpsService.shutdown();
if (mUsageStatsService != null) {
mUsageStatsService.prepareShutdown();
}
mBatteryStatsService.shutdown();
synchronized (this) {
mProcessStats.shutdownLocked();
notifyTaskPersisterLocked(null, true);
}
return timedout;
}
在rebootOrShutdown会执行PowerManagerService中的lowLevelReboot和lowLevelShutdown方法
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) {
// vibrate before shutting down
//关机震动
Vibrator vibrator = new SystemVibrator(context);
try {
//SHUTDOWN_VIBRATE_MS大概200毫秒
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);
}
...
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);//关闭电源
}
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)) {
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";
}
SystemProperties.set("sys.powerctl", "reboot," + reason);
try {
Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
而在PowerManagerService的
lowLevelReboot的 SystemProperties.set("sys.powerctl", "reboot," + reason);
类型如何:
sys.powerctl = reboot,
sys.powerctl = reboot,recovery
而lowLevelShutdown只是往SystemProperties.set("sys.powerctl", "shutdown," + reason);
类型例如:
sys.powerctl = shutdown, userrequested
sys.powerctl = 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);
}
通过SystemProperties把设置sys.powerctl这个字段的值往下传递,在init.cpp中
shutdown_command保存value (手动关机为:shutdown, userrequested)
do_shutdown则置为true
system/core/init/init.cpp
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();
}
}
}
在init.cpp的main函数while(true)的HandlePowerctlMessage接收value值做具体的关机操作
int main(int argc, char** argv) {
....
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {
...
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;
}
}
...
...
}
而HandlePowerctlMessage是在system/core/init/reboot.cpp
command匹配shutdown,reboot等之后,将cmd设值成对应的值传入
DoReboot(cmd, command, reboot_target, run_fsck);
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;
}
} else if (cmd_params[0] == "reboot") {
cmd = ANDROID_RB_RESTART2;
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
// 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;
}
}
// If there is an additional bootloader parameter, pass it along
if (cmd_params.size() == 3) {
reboot_target += "," + cmd_params[2];
}
}
} else if (command == "thermal-shutdown") { // no additional parameter allowed
// run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
} else {
command_invalid = true;
}
...
...
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 std::vector<std::string>&) {
DoReboot(cmd, command, reboot_target, run_fsck);
return 0;
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
// Skip wait for prop if it is in progress
ResetWaitForProp();
// Skip wait for exec if it is in progress
if (ServiceManager::GetInstance().IsWaitingForExec()) {
ServiceManager::GetInstance().ClearExecWait();
}
return true;
}
void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
bool runFsck) {
...
...
ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
if (kill_after_apps.count(s->name())) {
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
s->Start();
s->SetShutdownCritical();
} else if (s->IsShutdownCritical()) {
s->Start(); // start shutdown critical service if not started
}
});
....
Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
s->SetShutdownCritical(); // will not check animation class separately
});
}
...
// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
if (shutdown_timeout > 0ms) {
...
// Ask all services to terminate except shutdown critical ones.
ServiceManager::GetInstance().ForEachService([](Service* s) {
if (!s->IsShutdownCritical()) s->Terminate();
});
...
}
...
// minimum safety steps before restarting
// 2. kill all services except ones that are necessary for the shutdown sequence.
ServiceManager::GetInstance().ForEachService([](Service* s) {
if (!s->IsShutdownCritical()) s->Stop();
});
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
// 3. send volume shutdown to vold
Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
if (voldService != nullptr && voldService->IsRunning()) {
ShutdownVold();
voldService->Stop();
} else {
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
if (kill_after_apps.count(s->name())) s->Stop();
});
// 4. sync, try umount, and optionally run fsck for user shutdown
sync();
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
// Follow what linux shutdown is doing: one more sync with little bit delay
sync();
if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, rebootTarget);
abort();
}
static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
LOG(INFO) << "Reboot ending, jumping to kernel";
....
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:
reboot(RB_POWER_OFF);
break;
}
// In normal case, reboot should not return.
PLOG(FATAL) << "reboot call returned";
abort();
}
进入kernel,kernel-4.4/kernel/reboot.c
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
* so that some mistake won't make this reboot the whole machine.
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
*/
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
...
...
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
if (ret < 0) {
ret = -EFAULT;
break;
}
buffer[sizeof(buffer) - 1] = '\0';
kernel_restart(buffer);
break;
....
}
从串口log上看[sys.powerctl]=[shutdown,userrequested]设置完成
[ 326.688377] <3>.(2)[1:init]init: PropSet [sys.powerctl]=[shutdown,userrequested] Done
[ 326.688451] <3>.(2)[1:init][name:socket&][mtk_net][socekt]socket_close[64932] refcnt: 3
[ 326.688585] <3>.(2)[1:init]init: Clear action queue and start shutdown trigger
[ 326.688794] <3>.(2)[1:init]init: processing action (shutdown_done) from (<Builtin Action>:0)
[ 326.688857] <3>.(2)[1:init]init: Reboot start, reason: shutdown,userrequested, rebootTarget:
[ 326.689690] <3>.(2)[1:init]init: Shutdown timeout: 0 ms
[ 326.689918] <3>.(2)[1:init]init: Sending signal 9 to service 'healthd' (pid 278) process group...
.......
[ 329.700482] <0>.(0)[1:init]init: Sending signal 9 to service 'lmkd' (pid 280) process group...
[ 330.136580] <2>.(2)[1:init]init: Sending signal 9 to service 'vold' (pid 241) process group...
[ 330.218627] <1>.(1)[1:init]init: Sending signal 9 to service 'adbd' (pid 316) process group...
[ 330.234608] <1>.(1)[1:init]init: Sending signal 9 to service 'logd' (pid 229) process group...