美文网首页
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 亮屏慢问题处理

    问题: 【指纹】灭屏下使用正确的指纹解锁,解锁成功背光亮但屏幕没亮 【偶现】滑动解锁后只显示壁纸,图标在4S后加载...

  • 前端优化之骨架屏探索

    首屏渲染问题 首屏渲染问题一直单页面应用的问题,如果网速慢或者服务器响应慢的话,页面没有做一些交互处理,就会出现长...

  • Android亮屏和熄屏控制

    一. 前言我们的Android应用程序很多需要和亮屏和熄屏打交道,比如闹钟的时候,需要保持亮屏,之后又需要熄屏。...

  • Android杂知识

    opencc(简繁体转换库)Android 截屏方式整理Android 保持屏幕常亮的几种方法Android分享一...

  • Android 唤醒手机亮屏并前台显示

    Android 唤醒手机亮屏并前台显示 目前网络上许多唤醒手机亮屏的方式在高版本上都失效了 下面是自己实现的方式 ...

  • Android Studio 图片适配/使用之SVG

    前言 适配可以说是Android的老大难问题了,Android厂商众多,设备碎片化严重.大屏小屏,全面屏,异形屏数...

  • Android 8.1 横屏切换灰竖屏崩溃问题

    最近适配android 8,遇到了横屏切换到竖屏就会崩溃问题,这个问题在android旧版本下是没问题。我们的Ap...

  • Android 横竖屏处理

    Android 手机一般都支持横竖屏旋转,系统也会提供一个设置,控制是否可以旋转。 界面旋转方向的决定因素 决定一...

  • Android异形屏处理

    public class NotchActivity extends Activity {@Overridepro...

  • Android从熄屏到亮屏

    一、系统服务——PowerManager PowerManager.java就是管理我们电源方面的功能的,当然也包...

网友评论

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

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