Android 是先启动FallbackHome,再启动Launcher,就导致了在Launcher启动之前,开机动画就退出了,产生黑屏现象。关于开机动画的退出流程,请参考:Android 11 开机动画启动流程分析

解决这个问题,思想就是将开机动画延长到Launcher启动后再退出,有两种方案:

  • 将performEnableScreen中的设置关闭开机动画属性的代码移动到Launcher绘制的地方
  • Launcher启动后,再调用WindowManagerService的enableScreenAfterBoot方法,设置mSystemBooted为true,让performEnableScreen继续往下执行,设置关闭开机动画

代码实现

方案一:
在APP绘制的时候,都会调用到ActivityRecord.java的onWindowsDrawn方法,调用栈如下:

onWindowsDrawn shortComponentName:com.android.settings/.FallbackHome
 java.lang.Exception
      at com.android.server.wm.ActivityRecord.onWindowsDrawn(ActivityRecord.java:5419)
      at com.android.server.wm.ActivityRecord.updateReportedVisibilityLocked(ActivityRecord.java:5544)
      at com.android.server.wm.ActivityRecord.onFirstWindowDrawn(ActivityRecord.java:5349)
      at com.android.server.wm.WindowState.performShowLocked(WindowState.java:4438)
      at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:375)
      at com.android.server.wm.DisplayContent.lambda$new$8$DisplayContent(DisplayContent.java:889)
      at com.android.server.wm.-$$Lambda$DisplayContent$qxt4izS31fb0LF2uo_OF9DMa7gc.accept(Unknown Source:4)
      at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1984)
      at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1974)
      at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4651)
      at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4550)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.ActivityRecord.forAllWindowsUnchecked(ActivityRecord.java:3641)
      at com.android.server.wm.ActivityRecord.forAllWindows(ActivityRecord.java:3636)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.TaskDisplayArea.forAllWindows(TaskDisplayArea.java:488)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1302)
      at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1319)
      at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:4016)
      at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:1070)
      at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:850)
      at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:807)
      at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:178)
      at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:127)
      at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:116)
      at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:58)
      at android.os.Handler.handleCallback(Handler.java:938)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:223)
      at android.os.HandlerThread.run(HandlerThread.java:67)
      at com.android.server.ServiceThread.run(ServiceThread.java:44)

所以实现方案如下:
1,在onWindowsDrawn方法中添加:

//启动的是home且不是FallbackHome,表示是Launcher,Launcher绘制再退出开机动画
if (isHomeIntent(intent) && shortComponentName != null && !shortComponentName.contains("FallbackHome")) {
            SystemProperties.set("service.bootanim.exit", "1");
            Log.e(TAG_WM, "real home....." + shortComponentName);

            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, data, null, 0);
                    data.recycle();
                }
            } catch (RemoteException ex) {
                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
            }
  }

2,将 performEnableScreen中的代码注释掉

//frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
private void performEnableScreen() {
//......
/*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.
				android.util.Log.d("test1","performEnableScreen2:",new Exception());
                SystemProperties.set("service.bootanim.exit", "1");
                mBootAnimationStopped = true;
            }

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

            try {
                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                if (surfaceFlinger != null) {
                    ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
					android.util.Log.d("test1","performEnableScreen3:",new Exception());
                    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) {
                ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
            }
            */
     	//......
     }
	

方案二

//frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
public static boolean isNeedDelayEnableScreenAfterBoot = false;
@Override
    public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                if (r == null) {
                    return;
                }
                //add:如果是FallbackHome,则设置延迟调用EnableScreenAfterBoot
                if (r.info.packageName.equals("com.android.settings") && r.info.name.equals("com.android.settings.FallbackHome")) {
            		isNeedDelayEnableScreenAfterBoot = true;
            	} else {
            		if (isNeedDelayEnableScreenAfterBoot) {
            			mWindowManager.enableScreenAfterBoot();
            		}
            		isNeedDelayEnableScreenAfterBoot = false;
            	}
            	//add end


@Override
  public void enableScreenAfterBoot(boolean booted) {
            writeBootProgressEnableScreen(SystemClock.uptimeMillis());
            //add:如果表示延迟启动,则在这里不调用enableScreenAfterBoot
			if (!isNeedDelayEnableScreenAfterBoot) {
               mWindowManager.enableScreenAfterBoot();
			}
            //mWindowManager.enableScreenAfterBoot();
            //add end
            synchronized (mGlobalLock) {
                updateEventDispatchingLocked(booted);
            }
        }


final void finishBooting() {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                Trace.TRACE_TAG_ACTIVITY_MANAGER);
        t.traceBegin("FinishBooting");

        synchronized (this) {
        	//add: 注意这里需要添加条件判断,否则导致fallbackhome 不退出
            if (!mBootAnimationComplete && !ActivityTaskManagerService.isNeedDelayEnableScreenAfterBoot) {

注意要增加条件判断,否则导致fallbackhome 不退出卡在开机动画。因为mBootAnimationComplete只有在bootAnimationComplete里设置为true。flase的情况下,finishBooting代码往下不会继续执行。而 bootAnimationComplete是在performEnableScreen最后才调用的。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐