美文网首页
Android 亮屏慢问题处理

Android 亮屏慢问题处理

作者: AK_Coffee | 来源:发表于2018-09-04 20:07 被阅读0次

    问题:

    【指纹】灭屏下使用正确的指纹解锁,解锁成功背光亮但屏幕没亮

    【偶现】滑动解锁后只显示壁纸,图标在4S后加载出来

    抖音有个activity在灭屏的时候都会启动,如果出现如下情况:

    06-2513:08:14.4899802799I am_create_activity: [0,150997160,80,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,NULL,NULL,NULL,276824064]

    06-2513:08:14.5459802799I am_restart_activity: [0,150997160,80,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity]

    06-2513:08:14.5539802799I am_set_resumed_activity: [0,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,minimalResumeActivityLocked]

    06-2513:08:14.5859802799I am_pause_activity: [0,150997160,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity]

    06-2513:08:14.62698013170I am_set_resumed_activity: [0,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,resumeTopActivityInnerLocked]

    06-2513:08:14.64298013170I am_resume_activity: [0,150997160,80,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity]

    06-2513:08:14.8329802973I am_finish_activity: [0,150997160,80,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,app-request]

    06-2513:08:14.8369802973I am_focused_stack: [0,0,1,finishActivity adjustFocus]

    06-2513:08:14.8539802973I am_pause_activity: [0,150997160,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity]

    06-2513:08:14.94898011678I am_set_resumed_activity: [0,com.android.launcher3/com.android.searchlauncher.SearchLauncher,resumeTopActivityInnerLocked]

    06-2513:08:14.97298011678I am_resume_activity: [0,257364849,3,com.android.launcher3/com.android.searchlauncher.SearchLauncher]

    06-2513:08:15.1359802973I am_failed_to_pause: [0,150997160,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,(none)]

    06-2513:08:15.27835713571I am_on_resume_called: [0,com.android.searchlauncher.SearchLauncher,RESUME_ACTIVITY]

    06-2513:08:20.3799801055I am_destroy_activity: [0,150997160,80,com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,finish-imm]

    06-2513:08:20.38983158315I am_on_stop_called: [0,com.ss.android.message.sswo.SswoActivity,destroy]

    06-2513:08:28.8349801054I am_pss : [3571,10027,com.android.launcher3,106524672,89603072,5540864]

    pause failed导致AMS这边会有一个超时等待的动作,需继续查找为啥会出现pause 超时。

    导致问题流程如下:

    1, 待机过程中,抖音会启动

    com.ss.android.ugc.aweme/com.ss.android.message.sswo.SswoActivity,由于处于待机状态,该activity会立刻进入pause状态;后来得知SswoActivity这个类是抖音专门用来保活的一个透明类。

    2,正常情况下,该activity在唤醒时会立刻finish(app request主动请求),然后在唤醒过程中Top Activity依然是Launcher,如果没有及时finish,则Top activity是该activity;

    3,如果Top activity是 抖音activity,最终还是会主动请求activity finish,触发抖音activity--->Launcher activity的切换过程;

    4,步骤3中的切换过程在 Keyguard lock情况下进行,这种情况下,在显示Launcher activity之前需要将将抖音的UI show过程走一次(WMS 在有keyguard locked情况下的APP 切换逻辑);

    5,由于该抖音activity没有UI show过程(该activity没有UI),所以该等待会一直存在,直到5s超时,从而导致issue中的情况。

    点亮解锁逻辑流程如下:

    设备点亮流程

    frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java

    唤醒源 -> updatePowerStateLocked ->

    updateDisplayPowerStateLocked -> requestPowerState

    requestPowerState的实现在DisplayPowerController.java中

    在这里有一个blockScreen的逻辑动作,为的就是当screen内容准备好后,才点亮屏幕。

    相关接口及主要代码:

    animateScreenStateChange -> setScreenState -> blockScreenOn

    private void blockScreenOn() {

    if (mPendingScreenOnUnblocker == null) {

            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWERSCREEN_ON_BLOCKED_TRACE_NAME, 0);

    mPendingScreenOnUnblocker new ScreenOnUnblocker();

    mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();

            Slog.i(TAG"Blocking screen on until initial contents have been drawn.");

        }

    }

    ScreenOnUnblocker的作用是在回调触发的时候,发送一个消息MSG_SCREEN_ON_UNBLOCKED出去,执行unblock的动作。

    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {

    @Override

    public void onScreenOn() {

    Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKEDthis);

            msg.setAsynchronous(true);

    mHandler.sendMessage(msg);

        }

    }

    回到setScreenState中,主要代码:

    mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);

    screenTurningOn的实现在PhoneWindowmanager中,screenTurningOn回调结束后,屏点亮,unblock之前的逻辑,打印相关消息。

    private void unblockScreenOn() {

    if (mPendingScreenOnUnblocker != null) {

    mPendingScreenOnUnblocker null;

    long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;

    Slog.i(TAG"Unblocked screen on after " + delay + " ms");

    //所以可以根据这里来判断屏亮耗时

            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWERSCREEN_ON_BLOCKED_TRACE_NAME, 0);

        }

    }

    // Called on the DisplayManager's DisplayPowerController thread.

    @Override

    public void screenTurningOn(final ScreenOnListener screenOnListener) {

    if (DEBUG_WAKEUP) Slog.i(TAG"Screen turning on...");

    //所以可以根据这里来判断屏亮开始触发点亮

    。。。

    //这里走有锁屏的流程

    if (mKeyguardDelegate != null) {

    mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);

    mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,

                        getKeyguardDrawnTimeout());

    mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);

    else {

    if (DEBUG_WAKEUP) Slog.d(TAG,

    "null mKeyguardDelegate: setting mKeyguardDrawComplete.");

                finishKeyguardDrawn();

            }

        }

    }

    从主要代码可以看到,这里触发PhoneWindowManager的screenTurningOn接口,等待Keyguard绘制完成,并设置了一个1s的timeout机制,超时系统就不会继续等待,强制执行finishKeyguardDrawn(),当keyguard正常绘制完成,回调到mKeyguardDrawnCallback,继续执行finishKeyguardDrawn()

    case MSG_KEYGUARD_DRAWN_COMPLETE:

    if (DEBUG_WAKEUP) Slog.w(TAG"Setting mKeyguardDrawComplete");

        finishKeyguardDrawn();

    break;

    case MSG_KEYGUARD_DRAWN_TIMEOUT:

        Slog.w(TAG"Keyguard drawn timeout. Setting mKeyguardDrawComplete");

        finishKeyguardDrawn();

    当keyguard绘制完成的时候,接着会等待后台所有visible的window绘制完成

    private void finishKeyguardDrawn() {

     。。。

    // ... eventually calls finishWindowsDrawn which will finalize our screen turn on

        // as well as enabling the orientation change logic/sensor.

        mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,

    WAITING_FOR_DRAWN_TIMEOUT);

    }

    WAITING_FOR_DRAWN_TIMEOUT是一个1s的延时逻辑。

    如果时间到了,还没有绘制完成,系统也不会一直等下去

    @Override

    public void waitForAllWindowsDrawn(Runnable callback, long timeout) {

    boolean allWindowsDrawn = false;

    synchronized (mWindowMap) {

    mWaitingForDrawnCallback = callback;

            getDefaultDisplayContentLocked().waitForAllWindowsDrawn();

    mWindowPlacerLocked.requestTraversal();

    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);

    if (mWaitingForDrawn.isEmpty()) {

    allWindowsDrawn = true;

    else {

    mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);

                checkDrawnWindowsLocked();

            }

        }

    if (allWindowsDrawn) {

            callback.run();

        }

    }

    超时后,会清掉mWaitingForDrawn,在执行回调的run方法

    case WAITING_FOR_DRAWN_TIMEOUT: {

    Runnable callback = null;

    synchronized (mWindowMap) {

            Slog.w(TAG_WM"Timeout waiting for drawn: undrawn=" mWaitingForDrawn);

    mWaitingForDrawn.clear();

    callback = mWaitingForDrawnCallback;

    mWaitingForDrawnCallback null;

        }

    if (callback != null) {

            callback.run();

        }

    break;

    }

    在看callback的实现,发送一个消息触发window绘制完成finishWindowsDrawn使能屏幕:

    final Runnable mWindowManagerDrawCallback new Runnable() {

    @Override

    public void run() {

    if (DEBUG_WAKEUP) Slog.i(TAG"All windows ready for display!");

    mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);

        }

    };

    private void finishWindowsDrawn() {

    synchronized (mLock) {

    if (!mScreenOnEarly || mWindowManagerDrawComplete) {

    return// Screen is not turned on or we did already handle this case earlier.

            }

    mWindowManagerDrawComplete true;

        }

    finishScreenTurningOn();

    }

    所以,从这里可以看出,上层影响屏亮的因素:

    锁屏绘制时长

    Visible的window绘制的时长

    到此,背光点亮。

    Activity转场显示主要逻辑(锁屏状态下)

    在锁屏显示状态下,当activityA->activityB切换的时候,会存在切换动画。

    AMS startActivity会调用到ActivityStackSupervisor.java中的realStartActivityLocked,这里只看主要逻辑:

    if (mKeyguardController.isKeyguardLocked()) {

        r.notifyUnknownVisibilityLaunched();

    }

    notifyUnknownVisibilityLaunched的实现在ActivityRecord中

    void notifyUnknownVisibilityLaunched() {

    // No display activities never add a window, so there is no point in waiting them for

        // relayout.

        if (!noDisplay) {

    mWindowContainerController.notifyUnknownVisibilityLaunched();

        }

    }

    接着看AppWindowContainerController中的实现:

    public void notifyUnknownVisibilityLaunched() {

    synchronized(mWindowMap) {

    if (mContainer != null) {

    mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);

            }

        }

    }

    最终实现在:

    /**

     * Notifies that {@param appWindow} has been launched behind Keyguard, and we need to wait until

     * it is resumed and relaid out to resolve the visibility.

     */

    void notifyLaunched(@NonNull AppWindowToken appWindow) {

    if (DEBUG_UNKNOWN_APP_VISIBILITY) {

            Slog.d(TAG"App launched appWindow=" + appWindow);

        }

        mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RESUME);

    }

    同样在AMS执行activity Resume生命周期的时候,会触发:

    /**

     * Notifies that {@param appWindow} has finished resuming.

     */

    void notifyAppResumedFinished(@NonNull AppWindowToken appWindow) {

    if (mUnknownApps.containsKey(appWindow)

    && mUnknownApps.get(appWindow) == UNKNOWN_STATE_WAITING_RESUME) {

    if (DEBUG_UNKNOWN_APP_VISIBILITY) {

                Slog.d(TAG"App resume finished appWindow=" + appWindow);

            }

    mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RELAYOUT);

        }

    }

    当relayout完成时,会清掉mUnknownApps

    /**

     * Notifies that {@param appWindow} has relaid out.

     */

    void notifyRelayouted(@NonNull AppWindowToken appWindow) {

    if (!mUnknownApps.containsKey(appWindow)) {

    return;

        }

    if (DEBUG_UNKNOWN_APP_VISIBILITY) {

            Slog.d(TAG"App relayouted appWindow=" + appWindow);

        }

    int state = mUnknownApps.get(appWindow);

    if (state == UNKNOWN_STATE_WAITING_RELAYOUT) {

    mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);

    mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated);

        }

    }

    接着我们直接看AppTransition.java中,关于切换流程prepareAppTransitionLocked

    mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);

    mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUTAPP_TRANSITION_TIMEOUT_MS);

    APP_TRANSITION_TIMEOUT_MS是一个5s的timeout机制,当超时了,系统也不会继续等待,而是强制继续执行。

    case APP_TRANSITION_TIMEOUT: {

    synchronized (mWindowMap) {

    if (mAppTransition.isTransitionSet() || !mOpeningApps.isEmpty()

                        || !mClosingApps.isEmpty()) {

    if (DEBUG_APP_TRANSITIONS || mWindowManagerDebugger.WMS_DEBUG_USER)

                        Slog.v(TAG_WM"*** APP TRANSITION TIMEOUT."

                        " isTransitionSet()=" mAppTransition.isTransitionSet()

    " mOpeningApps.size()=" mOpeningApps.size()

    " mClosingApps.size()=" mClosingApps.size());

    mAppTransition.setTimeout();//设置超时flag

    mWindowPlacerLocked.performSurfacePlacement();//强制绘制,不等待

            }

        }

    直接看performSurfacePlacement的主要逻辑

    // If we are ready to perform an app transition, check through all of the app tokens to be

    // shown and see if they are ready to go.

    if (mService.mAppTransition.isReady()) {

        defaultDisplay.pendingLayoutChanges |=

                surfacePlacer.handleAppTransitionReadyLocked();

    if (DEBUG_LAYOUT_REPEATS)

            surfacePlacer.debugLayoutRepeats("after handleAppTransitionReadyLocked",

                    defaultDisplay.pendingLayoutChanges);

    }

    int handleAppTransitionReadyLocked() {

    int appsCount = mService.mOpeningApps.size();

    //如果这里return了,后面就不会触发,界面就没内容

    if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {

    return 0;

        }

        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER"AppTransitionReady");

    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG"**** GOOD TO GO");

    int transit = mService.mAppTransition.getAppTransition();

    if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {

            transit = AppTransition.TRANSIT_UNSET;

        }

    mService.mSkipAppTransitionAnimation false;

    mService.mNoAnimationNotifyOnTransitionFinished.clear();

        //界面显示成功,转场完成,remove掉之前的timeout消息

    mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);

    }

    transitionGoodToGo的实现,这里只看与该问题相关的逻辑代码:

    private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {

    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,

    "Checking " + appsCount + " opening apps (frozen="

                        mService.mDisplayFrozen " timeout="

                        mService.mAppTransition.isTimeout() + ")...");

    if (!mService.mAppTransition.isTimeout()) {

            ...

            //如果这里mUnknownApps不为空,那么说明relayout没有完成,直接return false

    不会触发后面GOOD TO GO的逻辑显示

    if (!mService.mUnknownAppVisibilityController.allResolved()) {

    if (DEBUG_APP_TRANSITIONS) {

                    Slog.v(TAG"unknownApps is not empty: "

                            mService.mUnknownAppVisibilityController.getDebugMessage());

                }

    return false;

            }

            ...

        }

    return true;

    }

    此该问题的相关逻辑已经梳理完成。

    目前针对这个问题在transitionGoodToGo做了一个规避操作

    if(!mService.mUnknownAppVisibilityController.allResolved() &&

    !mService.mUnknownAppVisibilityController.getDebugMessage().contains("com.ss.android.message.sswo.SswoActivity")) {

    if(DEBUG_APP_TRANSITIONS) {

    Slog.v(TAG,"fix unknownApps is not empty: "

                                + mService.mUnknownAppVisibilityController.getDebugMessage());

                    }

    returnfalse;

                }

    相关文章

      网友评论

          本文标题:Android 亮屏慢问题处理

          本文链接:https://www.haomeiwen.com/subject/trpnwftx.html