In Depth : Android Shutdown Sequence

  • What happened when I long press power button ?
  • What is shutdown sequence ?
  • How is it different from desktop linux shutdown sequence?
  • How to change shutdown menu ?

Many questions pop-up in mind when we think about Android shutdown sequence. Before you read about shutdown sequence I suggest you to read about boot sequence article.

Android is linux based open source operating system, x86 (x86 is a series of computer microprocessor instruction set architectures based on the Intel 8086 CPU.) is most likely system where linux kernel is deployed however all Android devices are running on ARM process (ARM (formerly Advanced RISC Machine, which was formerly Acorn RISC Machine)) except Intel’s Xolo device (http://xolo.in/xolo-x900-features). Xolo comes with Atom 1.6 GHz x86 processor. Android shutdown sequence is different from desktop linux like ubuntu, fedora, etc.

In this article I am going to explain shutdown sequence for Android only. Please refer “Linux Boot and Shutdown Process” for details of desktop linux shutdown process.

Following diagram illustrate shutdown sequence in detail.

Android Shutdown Sequence

Step 1: Long Press Power Button for 500ms.

Step 2: PhoneWindowManager.java identify Power Button long press and call method named “interceptKeyBeforeQueueing”.

Following code display power key  snippet from the function.

01 /** {@inheritDoc} */
02 @Override
03 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
04 ....
05 ....
06 ....
07 case KeyEvent.KEYCODE_POWER: {
08      result &= ~ACTION_PASS_TO_USER;
09        if (down) {
10          if (isScreenOn && !mPowerKeyTriggered
11                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
12                    mPowerKeyTriggered = true;
13                    mPowerKeyTime = event.getDownTime();
14                    interceptScreenshotChord();
15             }
16                ITelephony telephonyService = getTelephonyService();
17                 boolean hungUp = false;
18                if (telephonyService != null) {
19                    try {
20                        if (telephonyService.isRinging()) {
21                            // Pressing Power while there's a ringing incoming
22                            // call should silence the ringer.
23                             telephonyService.silenceRinger();
24                        else if ((mIncallPowerBehavior
25                                 & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
26                                && telephonyService.isOffhook()) {
27                             // Otherwise, if "Power button ends call" is enabled,
28                            // the Power button will hang up any current active call.
29                             hungUp = telephonyService.endCall();
30                        }
31                    catch (RemoteException ex) {
32                         Log.w(TAG, "ITelephony threw RemoteException", ex);
33                    }
34                }
35                interceptPowerKeyDown(!isScreenOn || hungUp
36                        || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
37            else {
38                mPowerKeyTriggered = false;
39                cancelPendingScreenshotChordAction();
40                if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
41                    result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
42                }
43                mPendingPowerKeyUpCanceled = false;
44            }
45           break;
46       }
47 ....
48 ....
49 ....
50 }

Above code handle multiple options like silence ringtone, take screenshots and power off. It will identify appropriate option based on time duration and other key’s status. It will call “interceptPowerKeyDown” option by eliminate other options.

Following code display interceptPowerKeyDown function. It will wait for 500 millisecond (ViewConfiguration#getGlobalActionKeyTimeout())
then call mPowerLongPress Thread.

1 private void interceptPowerKeyDown(boolean handled) {
2   mPowerKeyHandled = handled;
3   if (!handled) {
4        mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
5   }
6 }

Following code represent mPowerLongPress thread

01 private final Runnable mPowerLongPress = new Runnable() {
02         @Override
03         public void run() {
04             // The context isn't read
05             if (mLongPressOnPowerBehavior < 0) {
06                 mLongPressOnPowerBehavior = mContext.getResources().getInteger(
07                         com.android.internal.R.integer.config_longPressOnPowerBehavior);
08             }
09             int resolvedBehavior = mLongPressOnPowerBehavior;
10             if (FactoryTest.isLongPressOnPowerOffEnabled()) {
11                 resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
12             }
13  
14             switch (resolvedBehavior) {
15             case LONG_PRESS_POWER_NOTHING:
16                 break;
17             case LONG_PRESS_POWER_GLOBAL_ACTIONS:
18                 mPowerKeyHandled = true;
19                 if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
20                     performAuditoryFeedbackForAccessibilityIfNeed();
21                 }
22                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
23                 showGlobalActionsDialog();
24                 break;
25             case LONG_PRESS_POWER_SHUT_OFF:
26             case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
27                 mPowerKeyHandled = true;
28                 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
29                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
30                 mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
31                 break;
32             }
33         }
34     };

Step 3: Controls goes to GlobalActions.java which is responsible to display dialogbox with various options like (Power Off, Airplan mode, Take screenshot and few toggle buttons), This dialog box has different options are per your OEM provider, model and Android OS version. GlobalAction class has method named showdialog() which is responsible to create object of Dialogbox with options.

01 void showGlobalActionsDialog() {
02     if (mGlobalActions == null) {
03         mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
04     }
05     final boolean keyguardShowing = keyguardIsShowingTq();
06     mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
07     if (keyguardShowing) {
08          // since it took two seconds of long press to bring this up,
09         // poke the wake lock so they have some time to see the dialog.
10         mKeyguardMediator.userActivity();
11     }
12 }

Screenshot_2013-08-16-10-47-09

Step 4: If user select “Power Off” option from the dialogbox then control again goes back to PhoneWindowManager, It will start shutdown process.

Step 5: Shutdown process initiate from ShutdownThread.java file’s shoutdowninner() function, It wil display confirmation dialog with ok / cancel button, If user select ok option then actual shutdown process starts.

Screenshot_2013-08-16-10-47-29

Step 6: beginShutdownSequence() function called when user select OK option from the dialog.

01 private static void beginShutdownSequence(Context context) {
02         synchronized (sIsStartedGuard) {
03             if (sIsStarted) {
04                 Log.d(TAG, "Shutdown sequence already running, returning.");
05                 return;
06             }
07             sIsStarted = true;
08         }
09  
10         // throw up an indeterminate system dialog to indicate radio is
11         // shutting down.
12         ProgressDialog pd = new ProgressDialog(context);
13         pd.setTitle(context.getText(com.android.internal.R.string.power_off));
14         pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
15         pd.setIndeterminate(true);
16         pd.setCancelable(false);
17         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
18  
19         pd.show();
20  
21         sInstance.mContext = context;
22         sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
23  
24         // make sure we never fall asleep again
25         sInstance.mCpuWakeLock = null;
26         try {
27             sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
28                     PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
29             sInstance.mCpuWakeLock.setReferenceCounted(false);
30             sInstance.mCpuWakeLock.acquire();
31         catch (SecurityException e) {
32             Log.w(TAG, "No permission to acquire wake lock", e);
33             sInstance.mCpuWakeLock = null;
34         }
35  
36         // also make sure the screen stays on for better user experience
37         sInstance.mScreenWakeLock = null;
38         if (sInstance.mPowerManager.isScreenOn()) {
39             try {
40                 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
41                         PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
42                 sInstance.mScreenWakeLock.setReferenceCounted(false);
43                 sInstance.mScreenWakeLock.acquire();
44             catch (SecurityException e) {
45                 Log.w(TAG, "No permission to acquire wake lock", e);
46                 sInstance.mScreenWakeLock = null;
47             }
48         }
49  
50         // start the thread that initiates shutdown
51         sInstance.mHandler = new Handler() {
52         };
53         sInstance.start();
54     }

Run method, start actual shutdown process 

001 public void run() {
002         BroadcastReceiver br = new BroadcastReceiver() {
003             @Override public void onReceive(Context context, Intent intent) {
004                 // We don't allow apps to cancel this, so ignore the result.
005                 actionDone();
006             }
007         };
008  
009         /*
010          * Write a system property in case the system_server reboots before we
011          * get to the actual hardware restart. If that happens, we'll retry at
012          * the beginning of the SystemServer startup.
013          */
014         {
015             String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
016             SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
017         }
018  
019         /*
020          * If we are rebooting into safe mode, write a system property
021          * indicating so.
022          */
023         if (mRebootSafeMode) {
024             SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
025         }
026  
027         Log.i(TAG, "Sending shutdown broadcast...");
028  
029         // First send the high-level shut down broadcast.
030         mActionDone = false;
031         Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
032         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
033         mContext.sendOrderedBroadcastAsUser(intent,
034                 UserHandle.ALL, null, br, mHandler, 0nullnull);
035  
036         final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
037         synchronized (mActionDoneSync) {
038             while (!mActionDone) {
039                 long delay = endTime - SystemClock.elapsedRealtime();
040                 if (delay <= 0) {
041                     Log.w(TAG, "Shutdown broadcast timed out");
042                     break;
043                 }
044                 try {
045                     mActionDoneSync.wait(delay);
046                 catch (InterruptedException e) {
047                 }
048             }
049         }
050  
051         Log.i(TAG, "Shutting down activity manager...");
052  
053         final IActivityManager am =
054             ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
055         if (am != null) {
056             try {
057                 am.shutdown(MAX_BROADCAST_TIME);
058             catch (RemoteException e) {
059             }
060         }
061  
062         // Shutdown radios.
063         shutdownRadios(MAX_RADIO_WAIT_TIME);
064  
065         // Shutdown MountService to ensure media is in a safe state
066         IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
067             public void onShutDownComplete(int statusCode) throws RemoteException {
068                 Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
069                 actionDone();
070             }
071         };
072  
073         Log.i(TAG, "Shutting down MountService");
074  
075         // Set initial variables and time out time.
076         mActionDone = false;
077         final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
078         synchronized (mActionDoneSync) {
079             try {
080                 final IMountService mount = IMountService.Stub.asInterface(
081                         ServiceManager.checkService("mount"));
082                 if (mount != null) {
083                     mount.shutdown(observer);
084                 else {
085                     Log.w(TAG, "MountService unavailable for shutdown");
086                 }
087             catch (Exception e) {
088                 Log.e(TAG, "Exception during MountService shutdown", e);
089             }
090             while (!mActionDone) {
091                 long delay = endShutTime - SystemClock.elapsedRealtime();
092                 if (delay <= 0) {
093                     Log.w(TAG, "Shutdown wait timed out");
094                     break;
095                 }
096                 try {
097                     mActionDoneSync.wait(delay);
098                 catch (InterruptedException e) {
099                 }
100             }
101         }
102  
103         rebootOrShutdown(mReboot, mRebootReason);
104     }

Step 7: With rebootOrShutdown() method controls transfer to the native function of com_android_server_power_PowerManagerService.cpp file, and finally control goes to android_reboot.c file which is final step of shutdown sequence.

1 static void nativeShutdown(JNIEnv *env, jclass clazz) {
2     android_reboot(ANDROID_RB_POWEROFF, 00);
3 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值