android关机流程
PhoneWindowManager.java接收到长按power按键
PhoneWindowManager.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
。。。
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延时发送关机的message,interceptPowerKeyUp是取消延时的message。如果取消到达时间内没有发送出去就被取消了。
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
。。。
if (hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
}
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
mScreenshotChordPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
cancelPendingPowerKeyAction();
。。
}
private void cancelPendingPowerKeyAction() {
if (!mPowerKeyHandled) {
mPowerKeyHandled = true;
mHandler.removeMessages(MSG_POWER_LONG_PRESS);
}
}
处理延时发送的Message,调用showGlobalActionsInternal,如果时间不够,达不到长按就remove掉message。
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_POWER_LONG_PRESS:
powerLongPress();
break;
}
}
。。。。
}
private void powerLongPress() {
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);
}
}
GlobalActions,弹出dialog,又systemui或者系统弹出
如果5秒内systemui弹出失败,关机对话框将由系统弹出。
GlobalActions.java
GlobalActionsclass
implements GlobalActionsListener {
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);
}
}
@Override
public void onGlobalActionsShown() {
if (DEBUG) Slog.d(TAG, "onGlobalActionsShown");
// SysUI is showing, remove timeout callbacks.
mHandler.removeCallbacks(mShowTimeout);
}
}
上面mStatusBarInternal.showGlobalActions();调用的SystemUI的对话框,操作在SystemuI内完成。他由LocalServices获取。
public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mHandler = new Handler();
mWindowManagerFuncs = windowManagerFuncs;
mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
// Some form factors do not have a status bar.
if (mStatusBarInternal != null) {
mStatusBarInternal.setGlobalActionsListener(this);
}
}
StatusBarManagerInternal是一个接口,那么获取的上面mStatusBarInternal对象应该是实现了StatusBarManagerInternal接口。
//添加service,与getService对应
public StatusBarManagerService(Context context, WindowManagerService windowManager) {
mContext = context;
mWindowManager = windowManager;
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
}
/**
* Private API used by NotificationManagerService.
*/
private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
private boolean mNotificationLightOn;
。。。
@Override
public void showGlobalActions() {
if (mBar != null) {
try {
mBar.showGlobalActionsMenu();
} catch (RemoteException ex) {}
}
}
。。。
}
这个mBar定义IStatusBar mBar,是一个跨进程的操作,从注解我们可以看出IStatusBar,来源status bar service.
SystemUI实现
CommandQueue.java
@Override
public void showGlobalActionsMenu() {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
mHandler.obtainMessage(MSG_SHOW_GLOBAL_ACTIONS).sendToTarget();
}
}
GlobalActionsComponent.java
public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
private Extension<GlobalActions> mExtension;
private IStatusBarService mBarService;
@Override
public void start() {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
.withPlugin(GlobalActions.class)
.withDefault(() -> new GlobalActionsImpl(mContext))
.build();
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
}
@Override
public void handleShowGlobalActionsMenu() {
mExtension.get().showGlobalActions(this);
}
}
最终:
public class GlobalActionsImpl implements GlobalActions {
private final Context mContext;
private final KeyguardMonitor mKeyguardMonitor;
private final DeviceProvisionedController mDeviceProvisionedController;
private GlobalActionsDialog mGlobalActions;
public GlobalActionsImpl(Context context) {
mContext = context;
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
}
@Override
public void showGlobalActions(GlobalActionsManager manager) {
if (mGlobalActions == null) {
final ContextThemeWrapper context = new ContextThemeWrapper(mContext,
android.R.style.Theme_Material_Light);
mGlobalActions = new GlobalActionsDialog(context, manager);
}
mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
mDeviceProvisionedController.isDeviceProvisioned());
}
}
GlobalActionsDialog负责显示关机,重启的对话框,在这里我们可以自定义关机对话框。
这里面对于关机,重启,安全模式是调用系统api完成的
//关机
mWindowManagerFuncs.shutdown();
//以安全模式重启
mWindowManagerFuncs.reboot(true);
//重启
mWindowManagerFuncs.reboot(false);
具体重启是如何操作,再看mWindowManagerFuncs对象的实现类GlobalActionsComponent。
GlobalActionsComponent.java
@Override
public void reboot(boolean safeMode) {
try {
mBarService.reboot(safeMode);
} catch (RemoteException e) {
}
}
mBarService的实现类
StatusBarManagerService.java
*/
@Override
public void reboot(boolean safeMode) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
// ShutdownThread displays UI, so give it a UI context.
// TINNO START
// Modified by Jameson.xu on 20171114 for VBNLITEIA-1113,device reset exception
if (safeMode) {
//ShutdownThread.rebootSafeMode(getUiContext(), false);
//safe reboot,should show dialog for user(CTS 3PL(windware) need);for safemode function,CDAAOB-224,DATE20180825
ShutdownThread.rebootSafeMode(getUiContext(), true);
} else {
ShutdownThread.reboot(getUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, true);
}
// TINNO END
});
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* 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.
// TINNO START
// Modified by Jameson.xu on 20171114 for VBNLITEIA-1113,device reset exception
mHandler.post(() ->
ShutdownThread.shutdown(getUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, true));
// TINNO END
} finally {
Binder.restoreCallingIdentity(identity);
}
}
最终在ShutdownThread处理
修改安全模式,关机。重启的提示就是在这里面了
ShutdownThread.java
/**
* 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);
}
/**
* 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);
}
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;
}
}
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
// TINNO BEGIN
// Modified by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
int resourceId = 0;
if (!TinnoFeature.FEATURE_REBOOT_DIALOG) {
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);
}
// TINNO END
Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
// TINNO BEGIN
// Added by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
int resourceIdTitle = 0;
int resourceIdMsg = 0;
if (TinnoFeature.FEATURE_REBOOT_DIALOG) {
if (mReboot && !mRebootSafeMode) {
resourceIdTitle = com.android.internal.R.string.reboot;
resourceIdMsg = longPressBehavior == 2
? com.android.internal.R.string.reboot_confirm_question
: com.android.internal.R.string.reboot_confirm;
} else if (mRebootSafeMode) {
resourceIdTitle = com.android.internal.R.string.reboot_safemode_title;
resourceIdMsg = com.android.internal.R.string.reboot_safemode_confirm;
} else {
resourceIdTitle = com.android.internal.R.string.power_off;
resourceIdMsg = longPressBehavior == 2
? com.android.internal.R.string.shutdown_confirm_question
: com.android.internal.R.string.shutdown_confirm;
}
}
// TINNO END
if (confirm) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
// TINNO BEGIN
// Modified by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
sConfirmDialog = new AlertDialog.Builder(context)
.setTitle(TinnoFeature.FEATURE_REBOOT_DIALOG
? resourceIdTitle
: (mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off))
.setMessage(TinnoFeature.FEATURE_REBOOT_DIALOG ? resourceIdMsg : 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();
// TINNO END
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
} else {
beginShutdownSequence(context);
}
}
private static class CloseDialogReceiver extends BroadcastReceiver
implements DialogInterface.OnDismissListener {
private Context mContext;
public Dialog dialog;
CloseDialogReceiver(Context context) {
mContext = context;
IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
dialog.cancel();
}
public void onDismiss(DialogInterface unused) {
mContext.unregisterReceiver(this);
}
}
上面那个类,包含关机动画,等许多操作,最后都会调用
PowerManagerService.lowLevelReboot(reason);
PowerManagerService.lowLevelShutdown(reason);
/**
* 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.set(“sys.powerctl”, “reboot,” + reason);或
SystemProperties.set(“sys.powerctl”, “shutdown,” + reason);通知 通知init 执行。
然后到源码System目录init.cpp ,reboot.cpp处理这些关机操作。