Android P FDE开机启动enable_screen到sf_stop_bootanim耗时

link:Android 8.1 开机启动流程的收尾_bootanimation开机动画结束和BOOT_COMPLETE广播发送流程整理

1.问题


FDE设备在输入图案密码start android时,boot_progress_enable_screen到sf_stop_bootanim花费15s

boot_progress_enable_screen    AMS启动完成后开始激活屏幕,从此以后屏幕才能响应用户的触摸,它在WindowManagerService发出退出开机动画的时间节点之前,而真正退出开机动画还会花费少许时间,具体依赖animation zip 包中的desc.txt。wm_boot_animation_done才是用户感知到的动画结束时间节点
sf_stop_bootanim    SF设置service.bootanim.exit属性值为1,标志系统要结束开机动画了,可以用来跟踪开机动画结尾部分消耗的时间
wm_boot_animation_done    开机动画结束,这一步用户能直观感受到开机结束

2.分析

enable_scrren到bootani finish从如下方法说起

//最后的值performEnableScreen: mDisplayEnabled=false mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=true mOnlyCore=false
@/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen() {
    synchronized(mWindowMap) {
        if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
                + " mForceDisplayEnabled=" + mForceDisplayEnabled
                + " mShowingBootMessages=" + mShowingBootMessages
                + " mSystemBooted=" + mSystemBooted
                + " mOnlyCore=" + mOnlyCore,   
                new RuntimeException("here").fillInStackTrace());
        if (mDisplayEnabled) {
            return;
        }
        if (!mSystemBooted && !mShowingBootMessages) {
            return;
        }

        if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {
            return;
        }

        // Don't enable the screen until all existing windows have been drawn.
        if (!mForceDisplayEnabled
                // TODO(multidisplay): Expand to all displays?
                && getDefaultDisplayContentLocked().checkWaitingForWindows()) {
            return;
        }

        //设置属性,通知surfaceflinger退出开机动画
        if (!mBootAnimationStopped) {
            Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
            // stop boot animation
            // formerly we would just kill the process, but we now ask it to exit so it
            // can choose where to stop the animation.
            SystemProperties.set("service.bootanim.exit", "1");
            mBootAnimationStopped = true;
        }

        if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
            if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
            return;
        }

        try {
            IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
            if (surfaceFlinger != null) {
                Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                        data, null, 0);
                data.recycle();
            }
        } catch (RemoteException ex) {
            Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
        }

        //写event log wm_boot_animation_done,sys log打印ENABLING SCREEN
        EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
        Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
        mDisplayEnabled = true;
        if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!");

        // Enable input dispatch.
        mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
    }

    try {
        mActivityManager.bootAnimationComplete();
    } catch (RemoteException e) {
    }

    mPolicy.enableScreenAfterBoot();

    // Make sure the last requested orientation has been applied.
    updateRotationUnchecked(false, false);
}

 

07-03 10:20:27.762  3015  3037 I WindowManager: performEnableScreen: mDisplayEnabled=false mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=true mOnlyCore=false
07-03 10:20:27.762  3015  3037 I WindowManager: java.lang.RuntimeException: here
07-03 10:20:27.762  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.-wrap6(Unknown Source:0)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5266)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at android.os.Handler.dispatchMessage(Handler.java:106)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at android.os.Looper.loop(Looper.java:164)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at android.os.HandlerThread.run(HandlerThread.java:65)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at com.android.server.ServiceThread.run(ServiceThread.java:46)
07-03 10:20:27.763  3015  3037 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true


//不会一次就ok,会多次,我这里时候出问题是卡在getDefaultDisplayContentLocked().checkWaitingForWindows,花费15s,因此检测为什么
07-03 10:20:26.756  3015  3030 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.832  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.851  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.869  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.879  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.895  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.913  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.916  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.939  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.089  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.095  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.135  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.144  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.226  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.249  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.261  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.312  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.357  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.762  3015  3037 I WindowManager: 	at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)

检查在如下位置return true了,大概是说有wallpaper keyguard statusbar之类没有画完

 @/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
boolean checkWaitingForWindows() {
    ...
    final WindowState visibleWindow = getWindow(w -> {
        if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
            return true;  //添加log发现这里一直return true
        }
        if (w.isDrawnLw()) {
            if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
                mHaveBootMsg = true;
            } else if (w.mAttrs.type == TYPE_APPLICATION
                    || w.mAttrs.type == TYPE_DRAWN_APPLICATION) {
                mHaveApp = true;
            } else if (w.mAttrs.type == TYPE_WALLPAPER) {
                mHaveWallpaper = true;
            } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
                mHaveKeyguard = mService.mPolicy.isKeyguardDrawnLw();
            }
        }
        return false;
    });

    ...
    if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM,
            "******** booted=" + mService.mSystemBooted
            + " msg=" + mService.mShowingBootMessages
            + " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp
            + " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled
            + " haveKeyguard=" + mHaveKeyguard);

    // If we are turning on the screen to show the boot message, don't do it until the boot
    // message is actually displayed.
    if (!mService.mSystemBooted && !mHaveBootMsg) {
        return true;
    }

    // If we are turning on the screen after the boot is completed normally, don't do so until
    // we have the application and wallpaper.
    if (mService.mSystemBooted
            && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) {
        return true;
    }

    return false;
}

搜索keygaurd字眼,发现keyguard show确认花费很长时间

keyguard显示从doKeyguardLocked到showLocked,这里添加log发现是卡在了checkVoldPassword

@/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
/**
 * Enable the keyguard if the settings are appropriate.
 */
private void doKeyguardLocked(Bundle options) {
    if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
        // Don't show keyguard during half-booted cryptkeeper stage.
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
        return;
    }

    // if another app is disabling us, don't show
    if (!mExternallyEnabled) {
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
        return;
    }

    // if the keyguard is already showing, don't bother
    if (mStatusBarKeyguardViewManager.isShowing()) {
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
        resetStateLocked();
        return;
    }

    // In split system user mode, we never unlock system user.
    if (!mustNotUnlockCurrentUser()
            || !mUpdateMonitor.isDeviceProvisioned()) {
        ...

        if (!lockedOrMissing && shouldWaitForProvisioning()) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
                    + " and the sim is not locked or missing");
            return;
        }

        boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
        if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
                && !lockedOrMissing && !forceShow) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
            return;
        }

        if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
            if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
            // Without this, settings is not enabled until the lock screen first appears
            setShowingLocked(false, mAodShowing);
            hideLocked();
            return;
        }
    }

    if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
    showLocked(options);
}
/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java
@Override
public boolean checkVoldPassword(int userId) throws RemoteException {
    ...
    final IStorageManager service = mInjector.getStorageManager();
    String password;
    long identity = Binder.clearCallingIdentity();
    try {
        password = service.getPassword();
        service.clearPassword();
    } finally {
        Binder.restoreCallingIdentity(identity);
    }
    //有图案密码,就去认证
    try {
        if (mLockPatternUtils.isLockPatternEnabled(userId)) {
            if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
                    null /* progressCallback */)
                            .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
                return true;
            }
        }
    } catch (Exception e) {
    }
    ...
    return false;
}


@Override
public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
        ICheckCredentialProgressCallback progressCallback) throws RemoteException {
    checkPasswordReadPermission(userId);
    return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
}

//锁屏checkpattern都是在这里,密码验证错误,一般都是gatekeeper返回是error
private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
        boolean hasChallenge, long challenge, int userId,
        ICheckCredentialProgressCallback progressCallback) throws RemoteException {

    VerifyCredentialResponse response = null;
    response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
            userId, progressCallback);
    // The user employs synthetic password based credential.
    if (response != null) {
        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
            mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
                    userId);
        }
        return response;
    }
    ...
    return response;
}  
    
    private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
            credentialType, boolean hasChallenge, long challenge, int userId,
            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
        if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
      ...

        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
            notifyActivePasswordMetricsAvailable(userCredential, userId);
            unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);

            final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
            Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
            unlockUser(userId, null, secret);  //here
        ...

            onAuthTokenKnownForUser(userId, authResult.authToken);
        }
        ...
    }

终于到我们卡住的位置了,接着看mActivityManager.unlockUser为什么15s也没有执行onFinished

@/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java   
    private void unlockUser(int userId, byte[] token, byte[] secret) {
        // TODO: make this method fully async so we can update UI with progress strings
        final CountDownLatch latch = new CountDownLatch(1);
        //定义listener
        final IProgressListener listener = new IProgressListener.Stub() {
            @Override
            public void onStarted(int id, Bundle extras) throws RemoteException {
                Log.d(TAG, "unlockUser started");
            }

            @Override
            public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
                Log.d(TAG, "unlockUser progress " + progress);
            }

            @Override
            public void onFinished(int id, Bundle extras) throws RemoteException {
                Log.d(TAG, "unlockUser finished");
                latch.countDown();
            }
        };

        //mActivityManager.unlockUser
        try {
            mActivityManager.unlockUser(userId, token, secret, listener);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }

        //没有调用onFinished的话,会等15s,然后timeout才能过去,这里就是我们开机慢的位置
        try {
            latch.await(15, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        ...
    }
//接下来看unlockUser干什么的,最终到UserController.java
/frameworks/base/services/core/java/com/android/server/am/UserController.java
boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) {
    final long binderToken = Binder.clearCallingIdentity();
    try {
        return unlockUserCleared(userId, token, secret, listener);
    } finally {
        Binder.restoreCallingIdentity(binderToken);
    }
}


private boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
        IProgressListener listener) {
    UserState uss;
    synchronized (mLock) {
        // Register the given listener to watch for unlock progress
        uss = mStartedUsers.get(userId);
        if (uss != null) {
            uss.mUnlockProgress.addListener(listener);  //这里是关于onfinish操作
            uss.tokenProvided = (token != null);
        }
    }
    // Bail if user isn't actually running
    if (uss == null) {
        notifyFinished(userId, listener);
        return false;
    }

    finishUserUnlocking(uss);
    ...
    for (int testUserId : userIds) {
        final UserInfo parent = mInjector.getUserManager().getProfileParent(testUserId);
        if (parent != null && parent.id == userId && testUserId != userId) {
            Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
                    + "): attempting unlock because parent was just unlocked");
            maybeUnlockUser(testUserId);
        }
    }

    return true;
}

 

//STATE_FINISHED就会回调onFinished,就不会timeout
@/frameworks/base/core/java/com/android/internal/util/ProgressReporter.java
public void addListener(@Nullable IProgressListener listener) {
    if (listener == null) return;
    synchronized (this) {
        mListeners.register(listener);
        switch (mState) {
            case STATE_INIT:
                // Nothing has happened yet
                break;
            case STATE_STARTED:
                try {
                    listener.onStarted(mId, null);
                    listener.onProgress(mId, mProgress, mExtras);
                } catch (RemoteException ignored) {
                }
                break;
            case STATE_FINISHED:
                try {
                    listener.onFinished(mId, null);
                } catch (RemoteException ignored) {
                }
                break;
        }
    }
}

//只有这里赋值
public void finish() {
    synchronized (this) {
        mState = STATE_FINISHED;
        notifyFinished(mId, null);
        mListeners.kill();
    }
}

 
private void finishUserUnlocking(final UserState uss) {
    uss.mUnlockProgress.start();
    // Call onBeforeUnlockUser on a worker thread that allows disk I/O
    FgThread.getHandler().post(() -> {
        uss.mUnlockProgress.setProgress(20);

        // Dispatch unlocked to system services; when fully dispatched,
        // that calls through to the next "unlocked" phase
        mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
                .sendToTarget();
    });
}

/**
 * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to
 * {@link UserState#STATE_RUNNING_UNLOCKED}.
 */
void finishUserUnlocked(final UserState uss) {
    ...
    mInjector.getUserManagerInternal().setUserState(userId, uss.state);
    uss.mUnlockProgress.finish();  //finish,理论上执行到这里就可以notifyFinish

    // Get unaware persistent apps running and start any unaware providers
    // in already-running apps that are partially aware
    if (userId == UserHandle.USER_SYSTEM) {
        mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
    }
    mInjector.installEncryptionUnawareProviders(userId);

    // Dispatch unlocked to external apps
    final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
    unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    unlockedIntent.addFlags(
            Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
    mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
            null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
            userId);

    final UserInfo info = getUserInfo(userId);
    if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
        mInjector.sendPreBootBroadcast(userId, quiet,
                () -> finishUserUnlockedCompleted(uss));
    } else {
        finishUserUnlockedCompleted(uss);
    }
}

 

3.结论

1.耗费15s是因为在执行mActivityManager.unlockUser没有回调完成,导致timeout,需要在继续加log看为什么会这样

2.把15s改小,不过这个AOSP的值,改小也只能规避而已

 

4.继续前序

---------------------------------------------------------------------------------

正如前面说 canDismissBootAnimation 是keygauard画完的判断,但是这里卡的是在checkWaitingForWindow,最后add log看应该是statusBars和NavigationBar导致

        if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {
            return;
        }

        // Don't enable the screen until all existing windows have been drawn.
        if (!mForceDisplayEnabled
                // TODO(multidisplay): Expand to all displays?
                && getDefaultDisplayContentLocked().checkWaitingForWindows()) {
            return;
        }

开机在systemReady时候执行keygaurd绘制,执行到doKeyguard时blocked在checkVoldPassword

@/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
/**
 * Enable the keyguard if the settings are appropriate.
 */
private void doKeyguardLocked(Bundle options) {

        if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
            if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
            // Without this, settings is not enabled until the lock screen first appears
            setShowingLocked(false, mAodShowing);
            hideLocked();
            return;
        }
    }

    if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
    showLocked(options);
}

 

从接下来看,systemBooted后,system会判断如果5s,keyguard没有finish drawn,会发送timeout通知

//可以add callback看是不是这里调用的
 /** {@inheritDoc} */
@Override
public void systemBooted() {
    bindKeyguard();
    synchronized (mLock) {
        mSystemBooted = true;
        if (mSystemReady) {
            mKeyguardDelegate.onBootCompleted();
        }
    }
    startedWakingUp();
    screenTurningOn(null);
    screenTurnedOn();
}


@Override
public void screenTurningOn(final ScreenOnListener screenOnListener) {
    if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");

    updateScreenOffSleepToken(false);
    synchronized (mLock) {
        mScreenOnEarly = true;
        mScreenOnFully = false;
        mKeyguardDrawComplete = false;
        mWindowManagerDrawComplete = false;
        mScreenOnListener = screenOnListener;

        if (mKeyguardDelegate != null) {
            mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
            mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
                    getKeyguardDrawnTimeout());  //5s 后发送timeout message
            mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
        } else {
            if (DEBUG_WAKEUP) Slog.d(TAG,
                    "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
            finishKeyguardDrawn();
        }
    }
}

//如果keyguard drawn 那么 remove MSG_KEYGUARD_DRAWN_TIMEOUT
private void finishKeyguardDrawn() {
    synchronized (mLock) {
        if (!mScreenOnEarly || mKeyguardDrawComplete) {
            return; // We are not awake yet or we have already informed of this event.
        }

        mKeyguardDrawComplete = true;
        if (mKeyguardDelegate != null) {
            mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
        }
        mWindowManagerDrawComplete = false;
    }

    // ... 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);
}

如果timeout会执行 finishKeyguardDrawn ,把 mKeyguardDrawComplete 置为true,同事等所有window Drawn

//开机时应该没启动完,timeout时间为5s,具体可以add log确认
private long getKeyguardDrawnTimeout() {
    final boolean bootCompleted =
            LocalServices.getService(SystemServiceManager.class).isBootCompleted();
    // Set longer timeout if it has not booted yet to prevent showing empty window.
    return bootCompleted ? 1000 : 5000;
}


private void finishKeyguardDrawn() {
    synchronized (mLock) {
        if (!mScreenOnEarly || mKeyguardDrawComplete) {
            return; // We are not awake yet or we have already informed of this event.
        }

        mKeyguardDrawComplete = true;
        if (mKeyguardDelegate != null) {
            mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
        }
        mWindowManagerDrawComplete = false;
    }

    // ... 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);
}

mKeyguardDrawComplete 置为true后,performEnableScreen 就会跳到 checkWaitingForWindow,检测是否所有window都drawn

    @Override
    public boolean canDismissBootAnimation() {
        synchronized (mLock) {
            return mKeyguardDrawComplete;
        }
    }

此时正常Navigationbar StatusBar WallPaper都会画好,window状态会从 DRAW_PENDING  依次到 HAS_DEAWN(4)

  /** This is set when there is no Surface */
    static final int NO_SURFACE = 0;
    /** This is set after the Surface has been created but before the window has been drawn. During
     * this time the surface is hidden. */
    static final int DRAW_PENDING = 1;
    /** This is set after the window has finished drawing for the first time but before its surface
     * is shown.  The surface will be displayed when the next layout is run. */
    static final int COMMIT_DRAW_PENDING = 2;
    /** This is set during the time after the window's drawing has been committed, and before its
     * surface is actually shown.  It is used to delay showing the surface until all windows in a
     * token are ready to be shown. */
    static final int READY_TO_SHOW = 3;
    /** Set when the window has been shown in the screen the first time. */
    static final int HAS_DRAWN = 4;

每次drawn状态变化都会调用 commitFinishDrawingLocked,最后打印finishDrawingLocked

    // This must be called while inside a transaction.
    boolean commitFinishDrawingLocked() {
        if (DEBUG_STARTING_WINDOW_VERBOSE &&
                mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
            Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
                    + drawStateToString());
        }
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
            return false;
        }
        if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
            Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
        }
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final AppWindowToken atoken = mWin.mAppToken;
        if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
    }


    boolean finishDrawingLocked() {
        final boolean startingWindow =
                mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
        if (DEBUG_STARTING_WINDOW && startingWindow) {
            Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
                    + drawStateToString());
        }

        boolean layoutNeeded = mWin.clearAnimatingWithSavedSurface();

        if (mDrawState == DRAW_PENDING) {
            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
                        + mSurfaceController);
            if (DEBUG_STARTING_WINDOW && startingWindow) {
                Slog.v(TAG, "Draw state now committed in " + mWin);
            }
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }

        return layoutNeeded;
    }

 

目前的问题就是P上并不会HAS_DRAWN,一直是在DRAW_PENDING 。

小结:

ANdroid O行为:当keyguard blocked时,发生timeout ,然后checkWaitingForWindow,此时在2s左右内,statusbar navigationbar wallpaper都会finish drawn,然后就会执行到bootAnimationComplete,bootAnimationComplete完成后unlockuser就会执行finish,keyguard就会收到notifyfinished从而show,直到开机

ANdorid P行为:当keyguard blocked时,发生timeout ,然后checkWaitingForWindow,此时在15sunlockuser timeout,dokeygaurd可以通过,然后statusbar navigationbar wallpaper才会陆续finish drawn,直到开机

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值