Android Framework层Power键关机流程(二,关机流程)

二,关机流程

从前一篇博文我们知道,当用户长按Power键时会弹出(关机、重新启动,飞行模式等选项)对话框,我们点击关机,则会弹出关机确认对话框。那么从选项对话框到关机确认对话框又是一个什么流程呢。以下我们在简单分析一下:

showGlobalActionsDialog()-->showDialog()-->handleShow()-->createDialog()-->onPress()-->shutdown()

PhoneWindowManager.java

void showGlobalActionsDialog() {

......

mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

......

}

GlobalActions.java

public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {

......

handleShow();

......

}

private void handleShow() {

......

mDialog = createDialog();

......

}

private GlobalActionsDialog createDialog(){

......

mItems = new ArrayList<Action>();

// first: power off

mItems.add(

new SinglePressAction(

com.android.internal.R.drawable.uirom_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(true);

}

public boolean onLongPress() {

mWindowManagerFuncs.rebootSafeMode(true);

return true;

}

public boolean showDuringKeyguard() {

return true;

}

public boolean showBeforeProvisioning() {

return true;

}

});

......

}

上述代码中的mWindowManagerFuncs实际上是WindowManagerService的对象,该对象有PhoneWindowManager的init的方法传入GlobalActions的构造函数中,并在上述代码中进行调用。

以下这一行代码是调用的关键代码。

mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);

以下是弹出“关机确认对话框”的堆栈:

01-16 18:08:21.497 D/bill    (  720): java.lang.Throwable

01-16 18:08:21.497 D/bill    (  720): at com.android.server.power.ShutdownThread.shutdown(ShutdownThread.java:175)

01-16 18:08:21.497 D/bill    (  720): at com.android.server.wm.WindowManagerService.shutdown(WindowManagerService.java:5783)01-16 18:08:21.497 D/bill    (  720):at com.android.internal.policy.impl.GlobalActions$2.onPress(GlobalActions.java:352)//WindowManagerService实现了接口WindowsManagerFuncs

01-16 18:08:21.497 D/bill    (  720): at com.android.internal.policy.impl.GlobalActions.onClick(GlobalActions.java:581)

01-16 18:08:21.497 D/bill    (  720): at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:952)

01-16 18:08:21.497 D/bill    (  720): at android.widget.AdapterView.performItemClick(AdapterView.java:299)

01-16 18:08:21.497 D/bill    (  720): at android.widget.AbsListView.performItemClick(AbsListView.java:1152)

01-16 18:08:21.497 D/bill    (  720): at android.widget.AbsListView$PerformClick.run(AbsListView.java:3014)

01-16 18:08:21.497 D/bill    (  720): at android.widget.AbsListView$3.run(AbsListView.java:3865)

01-16 18:08:21.497 D/bill    (  720): at android.os.Handler.handleCallback(Handler.java:808)

01-16 18:08:21.497 D/bill    (  720): at android.os.Handler.dispatchMessage(Handler.java:103)

01-16 18:08:21.497 D/bill    (  720): at android.os.Looper.loop(Looper.java:193)

01-16 18:08:21.497 D/bill    (  720): at android.os.HandlerThread.run(HandlerThread.java:61)

从这里(shutdown())我们正式进入关机流程的关键。

shutdown()<ShutdownThread.java> --->shutdownInner() --->beginShutdownSequence()--->run()--->rebootOrShutdown()--->lowLevelShutdown()<PowerManagerService.java>--->

源代码来自:https://github.com/android/platform_frameworks_base/blob/master/services/java/com/android/server/power/ShutdownThread.java

 public static void shutdown(final Context context, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        shutdownInner(context, confirm);
    }

注!

參数2:confir;关机操作前是否须要用户进行确认

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);

        //longPressBehavior的值标示当前长按Power操作意向(关机、重新启动。

。。)

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);

if (sConfirmDialog != null) {

sConfirmDialog.dismiss();

}

sConfirmDialog = 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 = sConfirmDialog;

sConfirmDialog.setOnDismissListener(closer);

sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

sConfirmDialog.show();

} else {

beginShutdownSequence(context);

}

}

注:上述代码中,假设须要用户确认关机操作,则会弹出对话框。在对话框的确认button被触发时,调用beginShutdownSequence()方法继续关机流程。假设无需用户确认,则直接调用beginShutdownSequence()进入下一个关机流程节点。

beginShutdownSequence()有些手机厂商经常会在这里加入一些定制功能,比如在对话框中加入“下次高速开机”。定制关机动画等等。

随后会依据不同平台进行解说。以下这张图是Android原生系统的关机画面(相应以下加粗显示的代码):

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();

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() {

};

sInstance.start();⑤

}

注解!

①上述红色代码中的作用主要是为了防止手机进入休眠状态。从代码中我们看到。此时通过PowerManager的newWakeLock方法生成了PowerManager.WakeLock对象。newWakeLock()是PowerManager中最为经常使用的方法,该对象是一种锁机制,通过该对象能够控制设备的电源状态。在生成WakeLock实例时通过第一个參数的传入仅仅开控制获取不同的WakeLock,主要是不同的lock对CPU,屏幕,键盘灯有不同的影响。例如以下:

  1. PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。

  2. SCREEN_DIM_WAKE_LOCK:保持CPU 运转。同意保持屏幕显示但有可能是灰的。同意关闭键盘灯
  3. SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转。同意保持屏幕高亮显示。同意关闭键盘灯
  4. FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

②Wake Lock 是一种锁的机制。仅仅要有人拿着这个锁,系统九五案发进入休眠,能够被用户动态程序和内核获得,这个锁能够使有超时的或者是没有超时的。超时的锁会在时间过去以后自己主动解锁。假设没有锁了,或者超时了。内核就会启动休眠的那套机制来进入休眠。PowerManager.WakeLock有加锁和解锁的两种状态。加锁的方式有两种。一种是永久的锁住,这样的锁除非是显示的放开,否则是不会解锁的。所以这样的锁用起来要很小心,另外一种锁是超时锁,这样的锁会在锁住一段时间后自己主动解锁。

sInstance.mCpuWakeLock.setReferenceCounted(false);是设置锁的方式为永久的锁住。

sInstance.mCpuWakeLock.acquire(); 加锁

④上述蓝色代码的作用是为了保证用户体验,保持屏幕、键盘的亮度

⑤接着启动关机线程,进入关机流程的下一个节点。

/**

* 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) {

actionDone();//这里用于接受关机广播,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") + (mRebootReason != null ? mRebootReason : "");

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...");

// First send the high-level shut down broadcast.

mActionDone = false;

Intent intent = new Intent(Intent.ACTION_SHUTDOWN);

intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

mContext.sendOrderedBroadcastAsUser(intent,

UserHandle.ALL, null, br, mHandler, 0, null, null);//发送关机广播

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) {

}

}

}

Log.i(TAG, "Shutting down activity manager...");

final IActivityManager am =

ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));

if (am != null) {

try {

am.shutdown(MAX_BROADCAST_TIME);//关闭ActivityManagerService

} catch (RemoteException e) {

}

}

Log.i(TAG, "Shutting down package manager...");

final PackageManagerService pm = (PackageManagerService)

ServiceManager.getService("package");

if (pm != null) {

pm.shutdown();//关闭PackageManagerService服务

}

// 关闭Radios

shutdownRadios(MAX_RADIO_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");

// Set initial variables and time out time.

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);//关闭MountService

} 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) {

}

}

}

rebootOrShutdown(mReboot, mRebootReason);

}

最后调用rebootOrShutdown()

public static void rebootOrShutdown(boolean reboot, String reason) {

if (reboot) {

Log.i(TAG, "Rebooting, reason: " + reason);

PowerManagerService.lowLevelReboot(reason);

Log.e(TAG, "Reboot failed, will attempt shutdown instead");

} else if (SHUTDOWN_VIBRATE_MS > 0) {

// vibrate before shutting down

Vibrator vibrator = new SystemVibrator();

try {

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) {

}

}

// Shutdown power

Log.i(TAG, "Performing low-level shutdown...");

PowerManagerService.lowLevelShutdown();//关闭电源

}

}

/**

* Low-level function turn the device off immediately, without trying

* to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.

*/

public static void lowLevelShutdown() {

SystemProperties.set("sys.powerctl", "shutdown");//这里通过改动Android属性进行关机

}

注:上述代码中,红色加粗部分为关机关键代码。我也能够通过adb 命令进行改动Android系统的属性进行关机,详细命令例如以下

adb shell setprop sys.powerctl shutdown

时间: 2024-08-01 23:35:48

Android Framework层Power键关机流程(二,关机流程)的相关文章

Android Framework层Power键关机流程(一,Power长按键操作处理)

一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManager开始分析,在分析前我这里打印了该方法的堆栈调用信息.大家可以参考一下. public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { ...... android.uti

如何从C++代码直接访问android framework层的WifiService

说到底,Java层的service就是就C++层的binder的封装,所以从原理上来讲通过C++代码直接访问android framework层的service是完全可能的,这篇文章以访问WifiService为例,讲解如何去实现这个功能. 费话少说,直接上代码: WifiTest.cpp #include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadSt

android framework层 学习笔记(一)

大体结构 最近在研究android framework层的开发.  先来一张frame work的源码结构图 1  api 文件夹  不清楚用途,该目录下只有一个current.txt 内容看上去像代码,先放一放 2  cmds 文件夹,顾名思义是android 所支持的 command (命令) 最明显就是里面第一个文件夹就是am ,对应着android中的am 命令. 其他的命令里面有C语言写的也有java+C的. 3    core  文件夹这个文件夹下面有四个文件 java jni re

怎样从C++代码直接訪问android framework层的WifiService

说究竟,Java层的service就是就C++层的binder的封装.所以从原理上来讲通过C++代码直接訪问android framework层的service是全然可能的,这篇文章以訪问WifiService为例,解说怎样去实现这个功能. 费话少说.直接上代码: WifiTest.cpp #include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadSt

Android 手动按power键上锁,没有锁屏提示音,无法恢复【单机必现】

测试步骤 [测试版本]T0606 [模块版本] NAVI锁屏:5.0.0.ck [测试步骤] 1.手动按power键上锁, [测试结果] 没有锁屏提示音,无法恢复[单机必现] [预期结果] 有提示音 [发生次数] 单机必现 从log可以找到 4321 05-25 16:58:23.779 886 32501 W SoundPool: sample 1 not READY 7641 05-25 16:58:33.879 886 32563 W SoundPool: sample 1 not REA

android framework层 学习笔记(二)

 /framework/cmds   部分 这部分主要是命令的实现部分. android 本身是支持一部分linux命令的,并且再次基础上android又添加了一些他自身独有的命令,而这些命令正在存放在/framework/cmds文件夹下面的. 先来看第一个例子: am am 命令,我没能在源码中找到解释am具体的作用的描述文档,我只能根据源码来自己形容他,这个是一个用于开启组件的命令,包括activity 还有 service . ok,我的描述结束,接下来看源码: public class

Android framework层JNI的使用浅析

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/42418977 JNI技术对于多java开发的朋友相信并不陌生,即(java native interface),本地调用接口,主要功能有以下两点: 1.java层调用C/C++层代码 2.C/C++层调用java层代码 可能有些人会觉得jni技术破坏了Java语言的跨平台性,有这种想法可能是因为你对java理解得还不够深,如果你看看jdk源码,你会发现在jdk里面大量使用了jni技术,而且

译android framework层的资源文件

1.将资源放入 frameworks/base/core/res/res/ 中的相应目录,假设要添加的资源是 drawable 类型,文件名为 test(后缀可能为xml或者png等等),则将文件放入 frameworks/base/core/res/res/drawable*/ 下. 2.仿照已有的同类型系统资源修改 framework/base/core/res/res/values/public.xml,public.xml中有两种类型的资源描述,一种是<java-symbol/>系统私

Android 7.0 Power 按键处理流程

Android 7.0  Power 按键处理流程 Power按键的处理逻辑由PhoneWindowManager来完成,本文只关注PhoneWindowManager中与Power键相关的内容,其他系统按键的处理类似也是在PhoneWindowManager中处理的.理解了power按键的处理再看其他系统按键的逻辑会容易的多也简单的多. 一.Power按键的上报 Power按键的上报流程与其余的按键处理流程一致,在按下power按键后驱动上报按键经InputManagerService处理按键