深入解析Android关机

下图详细阐释了Android的关机顺序。

第一步: 按住电源按钮半秒钟(500ms)。

第二步: 之后,PhoneWindowManager.java 将捕获长按电源按钮这一事件并调用“interceptKeyBeforeQueueing”方法。

下面是处理长按电源键事件的代码片段

 1     /** {@inheritDoc} */
 2     @Override
 3     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
 4     ....
 5     ....
 6     ....
 7     case KeyEvent.KEYCODE_POWER: {
 8          result &= ~ACTION_PASS_TO_USER;
 9            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                                // 如果在来电响铃时按下电源键,则系统将关闭来电提示
22                                 telephonyService.silenceRinger();
23                            } else if ((mIncallPowerBehavior
24                                     & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
25                                    && telephonyService.isOffhook()) {
26                                 // 如果处在通话中且电源键挂断选项已启用,则按下电源键会结束当前通话
27                                 hungUp = telephonyService.endCall();
28                            }
29                        } catch (RemoteException ex) {
30                             Log.w(TAG, "ITelephony threw RemoteException", ex);
31                        }
32                    }
33                    interceptPowerKeyDown(!isScreenOn || hungUp
34                            || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
35                } else {
36                    mPowerKeyTriggered = false;
37                    cancelPendingScreenshotChordAction();
38                    if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
39                        result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
40                    }
41                    mPendingPowerKeyUpCanceled = false;
42                }
43               break;
44           }
45     ....
46     ....
47     ....
48     } 

上面的代码包含了对多种情形下对长按电源键时间的处理,例如静默来电响铃、屏幕截图以及关闭电源等。 系统将根据电源键被按住的时间长短以及相关按 键的使用情况来决定如何恰当地处理当前的用户操作。 当电源键被按下且没有截屏操作触发时interceptPowerKeyDown 将被调用,这时其 他的按键响应(其他按键响应指 interceptKeyBeforeQueueing 中其他cases)将不会被触发。

下面的代码展示了 interceptPowerKeyDown 函数内容, 函数将注册一个回调函数,在500毫秒超时事件 (ViewConfiguration#getGlobalActionKeyTimeout())触发时启动 mPowerLongPress 线程。

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

mPowerLongPress 线程的实现如下:

 1     private final Runnable mPowerLongPress = new Runnable() {
 2             @Override
 3             public void run() {
 4                 // The context isn‘t read
 5                 if (mLongPressOnPowerBehavior < 0) {
 6                     mLongPressOnPowerBehavior = mContext.getResources().getInteger(
 7                             com.android.internal.R.integer.config_longPressOnPowerBehavior);
 8                 }
 9                 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         }; 

第三步: 由上面代码的Switch分支可知,当程序进去 Long_Press_Power_Global_Options时控制将移交给 GlobalActions 类, 该模块则负责显示关机选项的对话 框,这些选项在各Android发行版(各OEM厂商定制的Android系统, 不同的手机型号和不同版本的Android系统)中不尽相同,通常包括 关闭电源、飞行模式和屏幕截图。也可能包括其他一些选项按键。GlobalActions 类实现了一个showdialog方法,该方法将根据当前系统 支持的菜单内容来创建这个对话框。

 1 void showGlobalActionsDialog() {
 2     if (mGlobalActions == null) {
 3         mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
 4     }
 5     final boolean keyguardShowing = keyguardIsShowingTq();
 6     mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
 7     if (keyguardShowing) {
 8          // 由于激活关机对话框需要长按电源键两秒以上,所以当对话框显示之后,屏幕的唤醒状态将被锁定,以方便用户浏览对话框中内容
 9         mKeyguardMediator.userActivity();
10     }
11 } 

第四步: 若用户选择“关闭电源“,则对系统的控制将交回给 PhoneWindowManager, 然后由PhoneWindowManager 启动关闭流程。

第五步: 整个关机过程起始于ShutdownThread模块中的shutdowninner方法。该方法首先创建一个确认对话框给用户, 用户可以选择确认关机或是取消关机操作。 如果用户选择确认,则系统将真正进入关机流程。

第六步: 如上所述,当用户点击确认按钮后beginShutdownSequence方法将被调用以启动关机顺序。

 1     private static void beginShutdownSequence(Context context) {
 2             synchronized (sIsStartedGuard) {
 3                 if (sIsStarted) {
 4                     Log.d(TAG, "Shutdown sequence already running, returning.");
 5                     return;
 6                 }
 7                 sIsStarted = true;
 8             }
 9
10             // 显示正在关闭电源的对话框
11             ProgressDialog pd = new ProgressDialog(context);
12             pd.setTitle(context.getText(com.android.internal.R.string.power_off));
13             pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
14             pd.setIndeterminate(true);
15             pd.setCancelable(false);
16
17     pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
18             pd.show();
19             sInstance.mContext = context;
20             sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
21             // 阻止CPU进入休眠状态
22             sInstance.mCpuWakeLock = null;
23             try {
24                 sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
25                         PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
26                 sInstance.mCpuWakeLock.setReferenceCounted(false);
27                 sInstance.mCpuWakeLock.acquire();
28             } catch (SecurityException e) {
29                 Log.w(TAG, "No permission to acquire wake lock", e);
30                 sInstance.mCpuWakeLock = null;
31             }
32             // 电源关闭前一直保持屏幕唤醒状态,以便提升用户体验
33             sInstance.mScreenWakeLock = null;
34             if (sInstance.mPowerManager.isScreenOn()) {
35                 try {
36                     sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
37                             PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
38                    sInstance.mScreenWakeLock.setReferenceCounted(false);
39                     sInstance.mScreenWakeLock.acquire();
40                 } catch (SecurityException e) {
41                     Log.w(TAG, "No permission to acquire wake lock", e);
42                     sInstance.mScreenWakeLock = null;
43                 }
44             }
45             // 启动负责关机顺序的线程
46             sInstance.mHandler = new Handler() {
47             };
48             sInstance.start();
49         } 

运行函数,启动实际的关机流程

  1     public void run() {
  2             BroadcastReceiver br = new BroadcastReceiver() {
  3                 @Override public void onReceive(Context context, Intent intent) {
  4                     // We don‘t allow apps to cancel this, so ignore the result.
  5                     actionDone();
  6                 }
  7             };
  8
  9             /*
 10              *  写入一个系统参数,以防Android系统中的System Server
 11              * (一个运行于Dalvik虚拟机与真实系统内核间的server,负责虚拟机与内核的通信)在真实硬件重启前完成重启。
 12              * 当上述情况发生时, 则在System Server完成启动后重试之前的重启操作。
 13              */
 14             {
 15                 String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
 16                 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
 17             }
 18
 19             /*
 20              * 写入一个系统参数以便重启后进入安全模式
 21              */
 22             if (mRebootSafeMode) {
 23                 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
 24             }
 25
 26             Log.i(TAG, "Sending shutdown broadcast...");
 27
 28             // 关闭移动通信
 29             mActionDone = false;
 30             Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
 31             intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
 32             mContext.sendOrderedBroadcastAsUser(intent,
 33                     UserHandle.ALL, null, br, mHandler, 0, null, null);
 34
 35             final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
 36             synchronized (mActionDoneSync) {
 37                 while (!mActionDone) {
 38                     long delay = endTime - SystemClock.elapsedRealtime();
 39                     if (delay <= 0) {
 40                         Log.w(TAG, "Shutdown broadcast timed out");
 41                         break;
 42                     }
 43                     try {
 44                         mActionDoneSync.wait(delay);
 45                     } catch (InterruptedException e) {
 46                     }
 47                 }
 48             }
 49
 50             Log.i(TAG, "Shutting down activity manager...");
 51
 52             final IActivityManager am =
 53                 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
 54             if (am != null) {
 55                 try {
 56                     am.shutdown(MAX_BROADCAST_TIME);
 57                 } catch (RemoteException e) {
 58                 }
 59             }
 60
 61             // 关闭移动通信
 62             shutdownRadios(MAX_RADIO_WAIT_TIME);
 63
 64             // 安全移除外部存储卡
 65             IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
 66                 public void onShutDownComplete(int statusCode) throws RemoteException {
 67                     Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
 68                     actionDone();
 69                 }
 70             };
 71
 72             Log.i(TAG, "Shutting down MountService");
 73
 74             // 初始化变量,并设置关机超时时限
 75             mActionDone = false;
 76             final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
 77             synchronized (mActionDoneSync) {
 78                 try {
 79                     final IMountService mount = IMountService.Stub.asInterface(
 80                             ServiceManager.checkService("mount"));
 81                     if (mount != null) {
 82                         mount.shutdown(observer);
 83                     } else {
 84                         Log.w(TAG, "MountService unavailable for shutdown");
 85                     }
 86                 } catch (Exception e) {
 87                     Log.e(TAG, "Exception during MountService shutdown", e);
 88                 }
 89                 while (!mActionDone) {
 90                     long delay = endShutTime - SystemClock.elapsedRealtime();
 91                     if (delay <= 0) {
 92                         Log.w(TAG, "Shutdown wait timed out");
 93                         break;
 94                     }
 95                     try {
 96                         mActionDoneSync.wait(delay);
 97                     } catch (InterruptedException e) {
 98                     }
 99                 }
100             }
101
102             rebootOrShutdown(mReboot, mRebootReason);
103         } 

第七步: 当rebootOrShutdown方法被调用时,系统控制权首先转至底层函 数 nativeShutdown(在com_android_server_power_PowerManagerService。cpp中定义) 并 最终调用android_reboot函数(定义于android_reboot.c中)来完成整个关机顺序

1     static void nativeShutdown(JNIEnv *env, jclass clazz) {
2         android_reboot(ANDROID_RB_POWEROFF, 0, 0);
3     }

注: 目前的Android版本的 rebootOrShutdown 的實現跟上面的不同。是通過調用PowerManagerService.lowLevelShutdown()修改屬性"sys.powerctl"的值實現的。可以參考: 设备驱动-----Android关机流程总结

完。

时间: 2024-11-05 17:23:36

深入解析Android关机的相关文章

Google工程师解析Android系统架构

导读:Sans Serif是Google的一位工程师,近日发布了一篇博文非常清楚的描述了Android系统架构,中国移动通信研究院院长黄晓庆在新浪微博上推荐了该文,并认为文中对Android的介绍很好,如下是CSDN对文章的简单编译: Andriod是什么? 首先,就像Android开源和兼容性技术负责人Dan Morrill在Android开发手册兼容性部分所解释的,"Android并不是传统的Linux风格的一个规范或分发版本,也不是一系列可重用的组件集成,Android是一个用于连接设备的

深入解析Android中Handler消息机制

Android提供了Handler 和 Looper 来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(MessageExchange).Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制. Handler的简单使用 为什么系统不允许子线程更新UI 因为的UI控件不是线程安全的. 如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访

解析Android的 消息传递机制Handler

1. 什么是Handler: Handler 网络释义"操纵者,管理者的"意思,在Android里面用于管理多线程对UI的操作: 2. 为什么会出现Handler: 在Android的设计机制里面,只允许主线程(一个程序第一次启动时所移动的线程,因为此线程主要是完成对UI相关事件的处理,所以也称UI线程) 对UI进行修改等操作,这是一种规则的简化,之所以这样简化是因为Android的UI操作时线程不安全的,为了避免多个线程同时操作UI造成线程安全 问题,才出现了这个简化的规则. 由此以

android 电池(二):android关机充电流程、充电画面显示【转】

本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下android关机充电是怎么.充电画面显示是怎么实现的,这个在工作中也比较有用,我们开始做这一块的时候也走了不少的弯路.我记得我们做adnroid2.3的时候,关机状态和充电logo显示是在uboot中做的.应该是有两种做法,回头我再看下uboot中做画面显示那一块是怎么做的,这一节我们重点说系统中的

源码解析Android中View的layout布局过程

Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文 < Android中View的布局及绘图机制>.量算是布局的基础,如果想了解量算的细节,可参见博文<源码解析Android中View的measure量算过程>.本文将从源码角度解析View的布局layout过程,本文会详细介绍View布局过程中的关键方法,并对源码加上了注释以进行说明. 对View进行布局的目的是计算

Android 解析 Android 项目组成

本文说明 Android 项目组成,虽然简单,但决不能忽视. 当你从简单 Hello World 程序,到会实现一些常见功能,比如,下拉(上拉)刷新最新(加载更多),消息处理(UI 通知更新),ViewPager 滑动效果,启动动画,访问网络文件,进行一些复杂的布局等等,在到调试一些开源项目,最后自己编写 Android 程序.可当调试一些开源项目时,尤其是那些比较大的开源项目,你会发现一些"意想不到"的情况,它们无论从界面,还是从功能,界面够炫,功能强大,也正因为如此,需要更多的资源

Android 关机充电,如果需要电量到100才显示绿灯,需要怎么修改?

前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net 雨季o莫忧离:http://blog.csdn.net/luckkof 正文 [DESCRIPTION] 默认在89平台关机充电中,电量到了90就会显示绿灯,如果需要到100才显示绿灯,需要 稍微修改一下code, 在这方面没有专门的接口. [PLATFORM] MT6589 [HOW TO DO] 下面的修改会apply到 IPO 以及KPOC.  若需要分开需

【转载】深度解析Android中字体设置

原文:http://mobile.51cto.com/android-265238.htm 1.在Android XML文件中设置字体 可以采用Android:typeface,例如android:typeface=”monospace”.在这里例子中我们在Activity中对android:text=”Hello, World! 您好”分别进行了四种显示方式,依次为“Sans”,“serif”,“monospace”和系统缺省方式(经试验缺省采用采用sans).英文字体有差异,貌似中文字体没有

【转】彻底解析Android缓存机制——LruCache

彻底解析Android缓存机制——LruCache 关于Android的三级缓存,其中主要的就是内存缓存和硬盘缓存.这两种缓存机制的实现都应用到了LruCache算法,今天我们就从使用到源码解析,来彻底理解Android中的缓存机制. 一.Android中的缓存策略 一般来说,缓存策略主要包含缓存的添加.获取和删除这三类操作.如何添加和获取缓存这个比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存还是硬盘缓存,它们的缓存大小都是有限的.当缓存满了之后,再想其添加缓存,这个时候就需要删除