Android 9.0 SystemUI 锁屏流程分析

1、锁屏界面显示的流程
在这里插入图片描述

2、按键灭屏 —> 按键亮屏

对于Key事件,InputDispatcher在分发之前会先将事件上发到PhoneWindowManager中,可以进行拦截,故从PhoneWindowManager的interceptKeyBeforeQueueing()方法开始分析按键灭屏,其中根据keyCode处理各种类型的Key事件。

PhoneWindowManager.java

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    if (!mSystemBooted) {
            // If we have not yet booted, don't let key events do anything.
            return 0;
        }  
    ...
    // Handle special keys.
        switch (keyCode) {
        ...
        	case KeyEvent.KEYCODE_POWER: {
                // 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键组合完成多种任务,如长按出现GlobalActionDialog、双击进入camera、power+音量下完成截屏等,故在按下处理灭屏是不合适的,将抬起事件处理为灭屏

private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
        ...
        if (!handled) {
            // Figure out how to handle the key now that it has been released.
            mPowerKeyPressCounter += 1;
    ...
            // No other actions.  Handle it immediately.
            powerPress(eventTime, interactive, mPowerKeyPressCounter);
        }
        // Done.  Reset our state.
        finishPowerKeyPress();
    }
private void powerPress(long eventTime, boolean interactive, int count) {
      ...
        if (count == 2) {
            powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
        } else if (count == 3) {
            powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
        } else if (interactive && !mBeganFromNonInteractive) {
            switch (mShortPressOnPowerBehavior) {
                case SHORT_PRESS_POWER_NOTHING:
                    break;
                case SHORT_PRESS_POWER_GO_TO_SLEEP:
                    goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                    break;
                ...
                }
            }
    }

这里的count是通过interceptPowerKeyUp()传递过来的,等于1。mShortPressOnPowerBehavior值是定义在config.xml中的,等于1,代表短按power键需要做的事

<!-- Control the behavior when the user short presses the power button.
            0 - Nothing
            1 - Go to sleep (doze)
            2 - Really go to sleep (don't doze)
            3 - Really go to sleep and go home (don't doze)
            4 - Go to home
            5 - Dismiss IME if shown. Otherwise go to home
    -->
    <integer name="config_shortPressOnPowerBehavior">1</integer>
private void goToSleep(long eventTime, int reason, int flags) {
        mRequestedOrGoingToSleep = true;
        mPowerManager.goToSleep(eventTime, reason, flags);
    }

导致灭屏的原因会有很多,定义在PowerManager中

PowerManager.java

/**
     * Go to sleep reason code: Going to sleep due by application request.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_APPLICATION = 0;

    /**
     * Go to sleep reason code: Going to sleep due by request of the
     * device administration policy.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1;

    /**
     * Go to sleep reason code: Going to sleep due to a screen timeout.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;

    /**
     * Go to sleep reason code: Going to sleep due to the lid switch being closed.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_LID_SWITCH = 3;

    /**
     * Go to sleep reason code: Going to sleep due to the power button being pressed.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_POWER_BUTTON = 4;

    /**
     * Go to sleep reason code: Going to sleep due to HDMI.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_HDMI = 5;

    /**
     * Go to sleep reason code: Going to sleep due to the sleep button being pressed.
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6;

    /**
     * Go to sleep reason code: Going to sleep by request of an accessibility service
     * @hide
     */
    public static final int GO_TO_SLEEP_REASON_ACCESSIBILITY = 7;
public void goToSleep(long time, int reason, int flags) {
        try {
            mService.goToSleep(time, reason, flags);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

接着调用PowerManagerService的goToSleep( )方法

PowerManagerService.java

@Override // Binder call
        public void goToSleep(long eventTime, int reason, int flags) {
            ...
            try {
                goToSleepInternal(eventTime, reason, flags, uid);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
        synchronized (mLock) {
            if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
                updatePowerStateLocked();
            }
        }
    }
private void updatePowerStateLocked() {
        ...
            // Phase 5: Send notifications, if needed.
            finishWakefulnessChangeIfNeededLocked();
      ...
    }
private void finishWakefulnessChangeIfNeededLocked() {
        if (mWakefulnessChanging && mDisplayReady) {
            ...
            mNotifier.onWakefulnessChangeFinished();
        }
    }

在这里调用到Notifier的onWakefulnessChangeFinished()方法

Notifier.java
 
 /**
     * Notifies that the device has finished changing wakefulness.
     */
    public void onWakefulnessChangeFinished() {
        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeFinished");
        }

        if (mInteractiveChanging) {
            mInteractiveChanging = false;
            handleLateInteractiveChange();
        }
    }
private void handleLateInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                // Finished waking up...
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mPolicy.finishedWakingUp();
                    }
                });
            } else {
                ...
                // Tell the policy we finished going to sleep.
                final int why = translateOffReason(mInteractiveChangeReason);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        ...
                        mPolicy.finishedGoingToSleep(why);
                    }
                });

                // Send non-interactive broadcast.
                mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
                mPendingGoToSleepBroadcast = true;
                updatePendingBroadcastLocked();
            }
        }
    }

当mInteractive为true时,点击power亮屏;为false时,灭屏;

最终调用到PhoneWindowManager的finishedGoingToSleep() 方法

PhoneWindowManager.java

// Called on the PowerManager's Notifier thread.
    @Override
    public void finishedGoingToSleep(int why) {
        ...
        if (mKeyguardDelegate != null) {
            mKeyguardDelegate.onFinishedGoingToSleep(why,
                    mCameraGestureTriggeredDuringGoingToSleep);
        }
        mCameraGestureTriggeredDuringGoingToSleep = false;
    }

接着调用KeyguardServiceDelegate的onFinishedGoingToSleep()方法

KeyguardServiceDelegate.java

public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
        if (mKeyguardService != null) {
            mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
        }
        mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
    }
KeyguardService.java

        @Override // Binder interface
        public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
            checkPermission();
            mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);
            mKeyguardLifecyclesDispatcher.dispatch(
                    KeyguardLifecyclesDispatcher.FINISHED_GOING_TO_SLEEP);
        }

最终调用到我们所熟悉的KeyguardViewMediator.java中

KeyguardViewMediator.java

    public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
        if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")");
        synchronized (this) {
            ...
            resetKeyguardDonePendingLocked();
            //如果灭屏之前Bouncer正在显示则需要通知其进入onPause状态
            notifyFinishedGoingToSleep();
            //cameraGestureTriggered为true代表不会显示锁屏,而是启动camera
            if (cameraGestureTriggered) {
                Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking.");

                // Just to make sure, make sure the device is awake.
                mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
                        "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
                mPendingLock = false;
                mPendingReset = false;
            }

            if (mPendingReset) {
                resetStateLocked();
                mPendingReset = false;
            }

            if (mPendingLock) {
                doKeyguardLocked(null);
                mPendingLock = false;
            }
    }

如果cameraGestureTriggered为false,则会调用resetStateLocked()和doKeyguardLocked(null)方法,而这两个方法最终都是通过StatusBarKeyguardViewManager的reset()方法进行锁屏。二者的区别是,resetStateLocked()因为已经在锁屏界面,不需要AMS、WMS修改锁屏窗口相关参数和Activity相关状态;doKeyguardLocked(null)会对是否显示进行一系列的条件判断,都验证通过才会show,比如第三方应用是否禁用了锁屏、是否在setup wizard界面等。

分析到doKeyguardLocked(null)方法后,接下来的流程就跟上述的锁屏界面显示流程一致。

参考文章:
AndroidQ SystemUI 之power键灭屏锁屏流程

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 9.0系统的U-Boot Logo加载流程如下: 首先,当设备上电时,启动引导加载程序(Bootloader)会运行。U-Boot作为一个常用的开源Bootloader,被广泛用于Android设备。然后,U-Boot开始执行它的初始化代码,包括初始化硬件、加载环境变量和配置等。 接下来,U-Boot开始加载Logo图像。在Android 9.0中,U-Boot会在启动过程的早期加载Logo图像,并在屏幕上显示。为了加载Logo图像,U-Boot需要的一些文件和配置如下: 1. Logo图像文件:通常是一个BMP格式的图片文件,作为设备启动时显示的Logo图像。这个文件会包含Logo图像的像素数据和相关的图像信息。 2. U-Boot配置文件:U-Boot需要通过一个配置文件来指定Logo图像的位置和属性。这个配置文件通常存储在设备的存储器中,如NAND Flash或eMMC闪存中。 3. 屏幕显示驱动:U-Boot还需要适配设备的屏幕显示驱动,以确保Logo图像可以正确显示在设备屏幕上。这包括配置屏幕分辨率、颜色深度等参数。 一旦U-Boot完成初始化和加载Logo图像所需的文件和配置,它会通过屏幕显示驱动将Logo图像显示在设备的屏幕上。Logo图像会持续显示一段时间,直到系统完成启动过程,然后才会被系统界面替换。 总结起来,Android 9.0的U-Boot Logo加载流程主要包括启动引导加载程序的初始化、配置加载、图像文件加载和屏幕显示等步骤。这样做的目的是为了在设备启动过程中提供一个包含品牌标识或其他相关信息的界面,以增强用户体验和品牌识别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值