全网最详细的Android11.0长按power键关机流程分析
Posted Mrsongs的心情杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全网最详细的Android11.0长按power键关机流程分析相关的知识,希望对你有一定的参考价值。
创作不易,请尊重原创,转载须注明出处:https://blog.csdn.net/An_Times/article/details/120027015
一、前言
本文将分析PhoneWindowMananger按键响应power键长按事件到SystemUI弹出关机界面dialog的流程。Android 原生的关机界面有两种,一种是LegacyGlobalActions中的dialog (第二张图),另一种是SystemUI中的GlobalActionsDialog(第一张图),常规情况下默认是弹出SystemUI中的关机界面,当SystemUI没有正常工作时才会弹出LegacyGlobalActions中的关机界面。
环境:本文基于MTK 6765 Android 11.0
二、PhoneWindowManager处理长按power键事件
- 代码路径:frameworks\\base\\services\\core\\java\\com\\android\\server\\policy\\PhoneWindowManager.java
- 按键事件从input子系统传递上来首选是经过PhoneWindowManager处理的,像一些系统比如关机键、音量键等等是在interceptKeyBeforeQueueing中处理并不会继续往下分发。
- power键按下的时候调用的是interceptPowerKeyDown方法。
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)
...此处省略部分代码
case KeyEvent.KEYCODE_POWER:
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
// 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;
...此处省略部分代码
- 长按power键最终调用的是powerLongPress() 方法。
private void powerLongPress()
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior)
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Global Actions");
showGlobalActionsInternal();
break;
...此处省略部分代码
- 长按power键弹框是调用showGlobalActionsInternal()方法。这个方法实际上调用的是GlobalActions 的showDialog 方法。
void showGlobalActionsInternal()
if (mGlobalActions == null)
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
// 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);
三、弹出关机界面Dialog
-
代码路径:frameworks\\base\\services\\core\\java\\com\\android\\server\\policy\\GlobalActions.java
else
-
showDialog方法中根据mGlobalActionsAvailable 变量来判断弹出哪一种关机界面dialog,即开头所说的,SystemUI弹的关机界面是mGlobalActionsProvider.showGlobalActions(),也就是下图这种,framework中原因的关机界面是mLegacyGlobalActions.showDialog。这里通过log打印mGlobalActionsAvailable的值为true,即说明正常用的是SystemUI中的关机界面。
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned)
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled())
return;
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = deviceProvisioned;
mShowing = true;
if (mGlobalActionsAvailable)
mHandler.postDelayed(mShowTimeout, 5000);
mGlobalActionsProvider.showGlobalActions();
else
// SysUI isn't alive, show legacy menu.
ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
三、GlobalActionsProvider 与SystemUI关联起来的过程
-
代码路径:frameworks\\base\\services\\core\\java\\com\\android\\server\\policy\\GlobalActionsProvider.java
-
GlobalActionsProvider是一个接口类,包含一个子接口类GlobalActionsListener,弹出关机界面主要是showGlobalActions 方法。其他地方是哪里调用了showGlobalActions呢,这里全局搜索一下GlobalActionsProvider即可。
package com.android.server.policy;
/** Used with LocalServices to add custom handling to global actions. */
public interface GlobalActionsProvider
/** @return @code true if the dialog is enabled. */
boolean isGlobalActionsDisabled();
/** Set the listener that will handle various global actions evetns. */
void setGlobalActionsListener(GlobalActionsListener listener);
/** Show the global actions UI to the user. */
void showGlobalActions();
/** Listener to pass global actions events back to system. */
public interface GlobalActionsListener
/**
* Called when sysui starts and connects its status bar, or when the status bar binder
* dies indicating sysui is no longer alive.
*/
void onGlobalActionsAvailableChanged(boolean available);
/**
* Callback from sysui to notify system that global actions has been successfully shown.
*/
void onGlobalActionsShown();
/**
* Callback from sysui to notify system that the user has dismissed global actions and
* it no longer needs to be displayed (even if sysui dies).
*/
void onGlobalActionsDismissed();
3.2、StatusBarManagerService 登场
-
代码路径:frameworks\\base\\services\\core\\java\\com\\android\\server\\statusbar\\StatusBarManagerService.java
-
第2节中 mGlobalActionsProvider.showGlobalActions()调用的实际上是mBar.showGlobalActionsMenu(),这里mBar就是IStatusBar。StatusBarManagerService相当于是客户端,全局搜索一下谁继承了IStatusBar.Stub 就是服务端了。
-
CommandQueue extends IStatusBar.Stub,说明CommandQueue是服务端。
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider()
@Override
public boolean isGlobalActionsDisabled()
// TODO(b/118592525): support global actions for multi-display.
final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
@Override
public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener)
mGlobalActionListener = listener;
mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
@Override
public void showGlobalActions()
if (mBar != null)
try
mBar.showGlobalActionsMenu();
catch (RemoteException ex)
;
3.3、CommandQueue的 showGlobalActionsMenu 方法
- 上文中提到mGlobalActionsProvider.showGlobalActions() 调用的实际上是CommandQueue 的showGlobalActionsMenu。
- 紧接着又调用了mCallbacks.get(i).handleShowGlobalActionsMenu(),这个Callbacks 是CommandQueue内部的一个接口类。我们看谁实现了这个Callbacks 接口就知道下一步调用的哪里了。
- 使用命令“grep -rn “implements Callbacks” vendor/mediatek/proprietary/packages/apps/SystemUI/” 最终查到是GlobalActionsComponent.java,那么下一步就看GlobalActionsComponent 的handleShowGlobalActionsMenu()方法就好了。
@Override
public void showGlobalActionsMenu()
synchronized (mLock)
mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
mHandler.obtainMessage(MSG_SHOW_GLOBAL_ACTIONS).sendToTarget();
...此处省略部分代码
case MSG_SHOW_GLOBAL_ACTIONS:
for (int i = 0; i < mCallbacks.size(); i++)
mCallbacks.get(i).handleShowGlobalActionsMenu();
3.4、GlobalActionsComponent 的handleShowGlobalActionsMenu()方法
- 看下mExtension定义:private Extension mExtension,那么实际是调用GlobalActions的showGlobalActions。
@Override
public void handleShowGlobalActionsMenu()
mStatusBarKeyguardViewManager.setGlobalActionsVisible(true);
mExtension.get().showGlobalActions(this);
3.5、SystemUI的GlobalActions
-
代码路径:vendor\\mediatek\\proprietary\\packages\\apps\\SystemUI\\plugin\\src\\com\\android\\systemui\\plugins\\GlobalActions.java
-
SystemUI的GlobalActions 跟framework中的GlobalActions 差不多,都是一个接口类,这里绕了一大圈还是调用同名的GlobalActions,这个过程确实很繁琐,可能是为了适配SystemUI的架构这样搞的。
-
“grep -rn “showGlobalActions” vendor/mediatek/proprietary/packages/apps/SystemUI/” 可以搜索到GlobalActionsImpl 中调用了showGlobalActions。
package com.android.systemui.plugins;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@ProvidesInterface(action = GlobalActions.ACTION, version = GlobalActions.VERSION)
@DependsOn(target = GlobalActionsManager.class)
public interface GlobalActions extends Plugin
String ACTION = "com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS";
int VERSION = 1;
void showGlobalActions(GlobalActionsManager manager);
default void showShutdownUi(boolean isReboot, String reason)
default void destroy()
@ProvidesInterface(version = GlobalActionsManager.VERSION)
public interface GlobalActionsManager
int VERSION = 1;
void onGlobalActionsShown();
void onGlobalActionsHidden();
void shutdown();
void reboot(boolean safeMode);
3.6、GlobalActionsImpl 调用showGlobalActions
- 代码路径:vendor\\mediatek\\proprietary\\packages\\apps\\SystemUI\\src\\com\\android\\systemui\\globalactions\\GlobalActionsImpl.java
- GlobalActionsImpl 的showGlobalActions实际上是mGlobalActionsDialog.showOrHideDialog,这里mGlobalActionsDialog 就是mGlobalActionsDialog,终于找到最终调用关机界面的地方了。
@Override
public void showGlobalActions(GlobalActionsManager manager)
if (mDisabled) return;
mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
mDeviceProvisionedController.isDeviceProvisioned(),
mWalletPluginProvider.get());
Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
四、最终的关机界面 GlobalActionsDialog
-
代码路径:vendor\\mediatek\\proprietary\\packages\\apps\\SystemUI\\src\\com\\android\\systemui\\globalactions\\GlobalActionsDialog.java
-
GlobalActionsDialog中有几个重要的方法,createDialog创建关机对话框;
-
关机界面有很多功能 例如关机、重启、静音都是像“ShutDownAction extends SinglePressAction implements LongPressAction” 这样形式实现的内部类。并且个功能单按点击是onPress() 方法,长按点击是
onLongPress() 方法。
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.systemui.globalactions;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.IActivityManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.UserInfo;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.sysprop.TelephonyProperties;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.transition.AutoTransition;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.ArraySet;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.util.ScreenRecordHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.view.RotationPolicy;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.MultiListLayout;
import com.android.systemui.MultiListLayout.MultiListAdapter;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.controls.ControlsServiceInfo;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.controls.management.ControlsAnimations;
import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.dagger以上是关于全网最详细的Android11.0长按power键关机流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 11.0 机器息屏瞬间立即按power键,机器亮屏并直接进入系统,不再锁屏
Android 11.0 修复长按关机键弹出框框时,按键盘任意键屏幕顶部状态栏会显示出来其他阴影