全网最详细的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 修复长按关机键弹出框框时,按键盘任意键屏幕顶部状态栏会显示出来其他阴影

深入了解PowerManagerService之Android 11.0 Power 键亮屏灭屏流程分析

Android开发中如何可以捕获到短按power键的事件

C程序实现监听长按物理power键3秒关机功能

Android 11.0 在闹钟APK,长按进入夜间模式,松开退出夜间模式