上一篇文章Android 开关机动画显示源码分析详细介绍了开关机动画的显示过程,Android系统开机时,在启动SurfaceFlinger服务过程中通过Android属性系统方式来启动bootanim进程,实现开机动画显示过程;当系统关机时,又是如何启动关机动画的呢?Android系统的整个关机流程又是怎样的呢?本文就针对这两个问题透过源码来给出具体的分析。我们知道,当长按电源键,系统会弹出关机提示对话框
当点击选择关机时,系统就会完成整个关机流程。接下来就通过源码来介绍Android关机流程的完整实现过程。当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
- ...
- switch (keyCode) {
- ...
- case KeyEvent.KEYCODE_POWER: {
- result &= ~ACTION_PASS_TO_USER;
- if (down) {
- if (isScreenOn && !mPowerKeyTriggered
- && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- mPowerKeyTriggered = true;
- mPowerKeyTime = event.getDownTime();
- interceptScreenshotChord();//抓屏
- }
- ITelephony telephonyService = getTelephonyService();
- boolean hungUp = false;
- if (telephonyService != null) {
- try {
- if (telephonyService.isRinging()) {
- //当来电时按下电源键,启动静音
- telephonyService.silenceRinger();
- } else if ((mIncallPowerBehavior
- & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
- && telephonyService.isOffhook()) {
- // Otherwise, if "Power button ends call" is enabled,
- // the Power button will hang up any current active call.
- hungUp = telephonyService.endCall();
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony threw RemoteException", ex);
- }
- }
- interceptPowerKeyDown(!isScreenOn || hungUp
- || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
- } else {
- ...
- }
- break;
- }
- ...
- }
- return result;
- }
- private void interceptPowerKeyDown(boolean handled) {
- mPowerKeyHandled = handled;
- if (!handled) {
- //隔500ms处理电源按键事件
- mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
- }
- }
- public void init(Context context, IWindowManager windowManager,WindowManagerFuncs windowManagerFuncs,
- LocalPowerManager powerManager) {
- ...
- mHandler = new PolicyHandler();
- ...
- }
- private final Runnable mPowerLongPress = new Runnable() {
- public void run() {
- // The context isn't read
- if (mLongPressOnPowerBehavior < 0) {
- mLongPressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- }
- switch (mLongPressOnPowerBehavior) {
- case LONG_PRESS_POWER_NOTHING:
- break;
- case LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- break;
- case LONG_PRESS_POWER_SHUT_OFF:
- mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- mWindowManagerFuncs.shutdown();
- break;
- }
- }
- };
通过读取配置文件取得config_longPressOnPowerBehavior配置的值为1,因此将显示关机对话框
- case LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- //向ActivityManagerService请求关闭所有窗口
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- //显示关机对话框
- showGlobalActionsDialog();
- break;
- void showGlobalActionsDialog() {
- //创建GlobalActions对象
- if (mGlobalActions == null) {
- mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
- }
- final boolean keyguardShowing = keyguardIsShowingTq();
- //显示对话框
- 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.
- mKeyguardMediator.pokeWakelock();
- }
- }
- 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() {
- //创建对话框
- mDialog = createDialog();
- prepareDialog();//设置对话框属性
- mDialog.show();//显示对话框
- mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
- }
- private AlertDialog createDialog() {
- //=========================创建对话框显示的列表项视图=====================================
- //每一个列表项被被抽象为Action对象,
- // 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);
- }
- //创建飞行模式切换ToggleAction对象
- 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) {
- 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);
- mHandler.removeMessages(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT,DELAY_AIRPLANE_SET_TIME);
- }
- }
- @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;
- }
- }
- public boolean showDuringKeyguard() {
- return true;
- }
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
- //更新当前飞行模式状态
- onAirplaneModeChanged();
- onRadioBusyStateChanged();
- mItems = new ArrayList<Action>();
- //向mItems列表中依次添加关机选择,飞行模式切换,静音模式选择
- // first: power off
- mItems.add(
- //创建关机SinglePressAction
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off,
- R.string.global_action_power_off) {
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- mWindowManagerFuncs.shutdown();
- }
- public boolean onLongPress() {
- mWindowManagerFuncs.rebootSafeMode();
- return true;
- }
- public boolean showDuringKeyguard() {
- return true;
- }
- public boolean showBeforeProvisioning() {
- return true;
- }
- });
- // next: airplane mode
- mItems.add(mAirplaneModeOn);
- // last: silent mode
- if (SHOW_SILENT_TOGGLE) {
- mItems.add(mSilentModeAction);
- }
- //获取系统中所有用户信息
- List<UserInfo> users = mContext.getPackageManager().getUsers();
- if (users.size() > 1) {//对于多用户Android系统,在显示的对话框下面添加用户切换选项
- UserInfo currentUser;
- try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
- } catch (RemoteException re) {
- currentUser = null;
- }
- for (final UserInfo user : users) {
- boolean isCurrentUser = currentUser == null
- ? user.id == 0 : (currentUser.id == user.id);
- SinglePressAction switchToUser = new SinglePressAction(
- com.android.internal.R.drawable.ic_menu_cc,
- (user.name != null ? user.name : "Primary")
- + (isCurrentUser ? " u2714" : "")) {
- public void onPress() {
- try {
- ActivityManagerNative.getDefault().switchUser(user.id);
- getWindowManager().lockNow();
- } catch (RemoteException re) {
- Log.e(TAG, "Couldn't switch user " + re);
- }
- }
- public boolean showDuringKeyguard() {
- return true;
- }
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
- mItems.add(switchToUser);
- }
- }
- mAdapter = new MyAdapter();//创建适配器,保存了所有数据,这里用MyAdapter保存列表项视图
- //=========================创建对话框=========================================
- final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
- ab.setAdapter(mAdapter, this).setInverseBackgroundForced(true);
- final AlertDialog dialog = ab.create();
- 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) {
- return mAdapter.getItem(position).onLongPress();//视图和数据相关联
- }
- });
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- dialog.setOnDismissListener(this);
- return dialog;
- }
各个列表项定义不同类型的Action,比如关机选项使用SinglePressAction来描述,目前Android系统定义了几种类型的Action,对应关机对话框中的不同选项。
将创建的列表选项添加到动态数组mItems中,并且为该对话框定义一个适配器MyAdapter,在单击对话框列表项时,调用适配器中对应的项来响应单击事件。Android适配器的使用实现了MVC编程模式,将数据和视图分开。通常我们将数据保存在一个数组中,通过适配器和视图控件关联显示,只不过这里的数据比较特殊,它是用来描述列表项显示的内容。
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position,long id) {
- return mAdapter.getItem(position).onLongPress();
- }
- public void onClick(DialogInterface dialog, int which) {
- if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
- dialog.dismiss();
- }
- mAdapter.getItem(which).onPress();
- }
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- mWindowManagerFuncs.shutdown();
- }
- public boolean onLongPress() {
- mWindowManagerFuncs.rebootSafeMode();
- return true;
- }
- final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
- public static WindowManagerPolicy makeNewWindowManager() {
- return sPolicy.makeNewWindowManager();
- }
Policy.java
- public WindowManagerPolicy makeNewWindowManager() {
- return new PhoneWindowManager();
- }
- private WindowManagerService(Context context, PowerManagerService pm,
- boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
- ...
- PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
- thr.start();
- synchronized (thr) {
- while (!thr.mRunning) {
- try {
- thr.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- ...
- }
- static class PolicyThread extends Thread {
- @Override
- public void run() {
- Looper.prepare();
- ...
- mPolicy.init(mContext, mService, mService, mPM);
- synchronized (this) {
- mRunning = true;
- notifyAll();
- }
- ...
- Looper.loop();
- }
- }
- public void init(Context context, IWindowManager windowManager,
- WindowManagerFuncs windowManagerFuncs,LocalPowerManager powerManager) {
- ...
- mWindowManagerFuncs = windowManagerFuncs;
- ...
- }
- public void shutdown() {
- ShutdownThread.shutdown(mContext, true);
- }
- public void rebootSafeMode() {
- ShutdownThread.rebootSafeMode(mContext, true);
- }
- public static void shutdown(final Context context, boolean confirm) {
- mReboot = false;
- mRebootSafeMode = false;
- shutdownInner(context, confirm);
- }
- static void shutdownInner(final Context context, boolean confirm) {
- // 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);
- 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);
- final AlertDialog dialog = 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 = dialog;
- dialog.setOnDismissListener(closer);
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.show();
- } else {//不显示关机确认对话框,直接进入关机流程
- beginShutdownSequence(context);
- }
- }
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Shutdown sequence already running, returning.");
- return;
- }
- sIsStarted = true;
- }
- // throw up an indeterminate system dialog to indicate radio is
- // shutting down.
- ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- //pd.show();
- shutdownTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_TIME;
- //执行关机动画
- String[] bootcmd = {"bootanimation", "shutdown"} ;
- try {
- Log.i(TAG, "exec the bootanimation ");
- SystemProperties.set("service.bootanim.exit", "0");
- Runtime.getRuntime().exec(bootcmd);
- } catch (Exception e){
- Log.e(TAG,"bootanimation command exe err!");
- }
- //初始化关机线程ShutdownThread
- 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;
- }
- }
- // start the thread that initiates shutdown
- sInstance.mHandler = new Handler() {
- };
- //启动关机线程ShutdownThread
- sInstance.start();
- }
- public void run() {
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
- // 用于接收关机广播
- actionDone();
- }
- };
- //写属性"sys.shutdown.requested"保存关机原因
- {
- String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
- SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
- }
- //如果是安全模式关机,写属性"persist.sys.safemode"
- if (mRebootSafeMode) {
- SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
- }
- Log.i(TAG, "Sending shutdown broadcast...");
- // First send the high-level shut down broadcast.
- mActionDone = false;
- //发送关机广播
- mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
- br, mHandler, 0, null, null);
- //等待10S,前面定义的广播接收器收到关机广播时mActionDone设置为true,同时取消等待
- 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;
- }
- try {
- mActionDoneSync.wait(delay);
- } catch (InterruptedException e) {
- }
- }
- }
- //10S时间内关闭ActivityManager服务
- final IActivityManager am =ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
- if (am != null) {
- try {
- am.shutdown(MAX_BROADCAST_TIME);
- } catch (RemoteException e) {
- }
- }
- //12s内关闭radios.
- shutdownRadios(MAX_RADIO_WAIT_TIME);
- //10s内关闭ICCS
- shutdownIccs(MAX_ICC_WAIT_TIME);
- // Shutdown MountService to ensure media is in a safe state
- IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
- public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
- actionDone();
- }
- };
- Log.i(TAG, "Shutting down MountService");
- //20s内关闭MountService服务
- mActionDone = false;
- final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
- synchronized (mActionDoneSync) {
- try {
- final IMountService mount = IMountService.Stub.asInterface(ServiceManager.checkService("mount"));
- if (mount != null) {
- mount.shutdown(observer);
- } else {
- Log.w(TAG, "MountService unavailable for shutdown");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception during MountService shutdown", e);
- }
- while (!mActionDone) {
- long delay = endShutTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "Shutdown wait timed out");
- break;
- }
- try {
- mActionDoneSync.wait(delay);
- } catch (InterruptedException e) {
- }
- }
- }
- //关机时间定义为5s,这里计算关机超过的时间
- long shutdownDelay = shutdownTime - SystemClock.elapsedRealtime();
- if (shutdownDelay > 0) {
- Log.i(TAG, "Shutdown delay:"+shutdownDelay);
- SystemClock.sleep(shutdownDelay);
- }
- //继续关机
- rebootOrShutdown(mReboot, mRebootReason);
- }
(1)发送关机广播ACTION_SHUTDOWN
(2)关闭ActivityManager 服务
(3)关闭无线相关的服务
(4)关闭Iccs
(5)关闭MountService服务
- public static void rebootOrShutdown(boolean reboot, String reason) {
- if (reboot) {//是否重启
- Log.i(TAG, "Rebooting, reason: " + reason);
- try {
- PowerManagerService.lowLevelReboot(reason);
- } catch (Exception e) {
- Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
- }
- } else if (SHUTDOWN_VIBRATE_MS > 0) {//震动时间为500ms
- // vibrate before shutting down
- Vibrator vibrator = new SystemVibrator();
- try {
- //关机震动500ms
- vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
- } 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) {
- }
- }
- //关闭电源
- Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown();
- }
- public static void lowLevelShutdown() {
- nativeShutdown();
- }
- static void nativeShutdown(JNIEnv *env, jobject clazz) {
- delFlag();
- android_reboot(ANDROID_RB_POWEROFF, 0, 0);
- }