Android T 远程动画显示流程(更新中)
序
本地动画和远程动画区别是什么?
本地动画:自给自足。对自身SurfaceControl矢量动画进行控制。
远程动画:拿来吧你!一个app A对另一个app B通过binder跨进程通信,控制app B的SurfaceControl矢量动画。
无论是本地动画还是远程动画,都仅仅只是对SurfaceControl动画图层控制,而无法控制应用内部的View。
注:矢量动画包含位移、放大、缩小、透明度、圆角等。
常见的远程动画,就是桌面与应用交互。比如,我们从桌面点击一个应用启动这个应用,这个过程中会产生的动画就是远程动画。
我们从这个角度分析其动画显示过程。
显示过程分析
我们前面通过学习Android T 窗口动画(本地动画)显示流程,发现无论什么类型动画都有其创建和移除的过程,在SurfaceAnimator中createAnimationLeash和removeLeash添加log打印堆栈信息。
createAnimationLeash
添加log
Slog.i("WindowManager","createAnimationLeash type = " + animationTypeToString(type) + " animatable = "+animatable, new Exception());
removeLeash
添加log
Slog.i("WindowManager","removeLeash leash = " + leash , new Exception());
我们看看下面几种启动的动画创建和移除的过程(排除了insets类型的动画):
冷启动
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x5e2271f
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0xebdcd79
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0xd323396
WindowManager: createAnimationLeash type = starting_reveal animatable = Window{a65f40b u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}
WindowManager: createAnimationLeash type = window_animation animatable = Window{dad6bc2 u0 Splash Screen com.example.mysystemdialog}
WindowManager: removeLeash leash = Surface(name=Surface(name=a65f40b com.example.mysystemdialog/com.example.mysystemdialog.MainActivity)/@0xdbce2c1 - animation-leash of starting_reveal)/@0x6df31a7
WindowManager: removeLeash leash = Surface(name=Surface(name=dad6bc2 Splash Screen com.example.mysystemdialog)/@0x3868f87 - animation-leash of window_animation)/@0x9d22add
应用不在后台运行,从桌面点击一个应用冷启动,动画顺序如下:
动画窗口 | 动画类型 | 操作 |
---|---|---|
mysystemdialog(Task) | app_transition | 创建 |
home(桌面Task) | app_transition | 创建 |
WallpaperWindowToken(壁纸) | window_animation | 创建 |
home(桌面Task) | app_transition | 移除 |
mysystemdialog(Task) | app_transition | 移除 |
WallpaperWindowToken(壁纸) | app_transition | 移除 |
MainActivity冷启动应用主界面(ActivityRecord) | starting_reveal | 创建 |
mysystemdialog的冷启动窗口(Splash Screen) | window_animation | 创建 |
MainActivity冷启动应用主界面(ActivityRecord) | starting_reveal | 移除 |
mysystemdialog的冷启动窗口(Splash Screen) | window_animation | 移除 |
热启动
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x6c5dc4f
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x8775329
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0x8534d86
WindowManager: createAnimationLeash type = window_animation animatable = Window{d22fcb2 u0 SnapshotStartingWindow for taskId=77}
WindowManager: removeLeash leash = Surface(name=Surface(name=d22fcb2 SnapshotStartingWindow for taskId=77)/@0xfcbebd0 - animation-leash of window_animation)/@0x3faeece
应用本身就在后台运行,从桌面热启动应用,动画顺序如下:
动画窗口 | 动画类型 | 操作 |
---|---|---|
mysystemdialog(Task) | app_transition | 创建 |
home(桌面Task) | app_transition | 创建 |
WallpaperWindowToken(壁纸) | window_animation | 创建 |
home(桌面Task) | app_transition | 移除 |
mysystemdialog(Task) | app_transition | 移除 |
WallpaperWindowToken(壁纸) | app_transition | 移除 |
mysystemdialog的热启动窗口(SnapshotStartingWindow) | window_animation | 创建 |
mysystemdialog的热启动窗口(SnapshotStartingWindow) | window_animation | 移除 |
home回到桌面
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x77da703
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x12ce9bd
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0x5e69f0a
在应用界面,点击home键退回到桌面界面,动画顺序如下:
动画窗口 | 动画类型 | 操作 |
---|---|---|
home(桌面Task) | app_transition | 创建 |
mysystemdialog(Task) | app_transition | 创建 |
WallpaperWindowToken(壁纸) | window_animation | 创建 |
mysystemdialog(Task) | app_transition | 移除 |
home(桌面Task) | app_transition | 移除 |
WallpaperWindowToken(壁纸) | window_animation | 移除 |
关键堆栈
创建动画 createAnimationLeash
桌面
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.lambda$build$4(WindowContainer.java:4078)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.$r8$lambda$BWeVZQp29j72z9D_sWdID2xR4qI(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda1.startAnimation(Unknown Source:7)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3174)
WindowManager: at com.android.server.wm.Task.applyAnimationUnchecked(Task.java:3366)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:2958)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:882)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1085)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:266)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
应用task
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.lambda$build$4(WindowContainer.java:4078)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.$r8$lambda$BWeVZQp29j72z9D_sWdID2xR4qI(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda1.startAnimation(Unknown Source:7)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3174)
WindowManager: at com.android.server.wm.Task.applyAnimationUnchecked(Task.java:3366)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:2958)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:882)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1087)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:266)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
壁纸
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.lambda$startWallpaperAnimations$0(WallpaperAnimationAdapter.java:82)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.$r8$lambda$pFt1sM34mQb-FFZsZckZ6IVTj_M(Unknown Source:0)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter$$ExternalSyntheticLambda0.accept(Unknown Source:13)
WindowManager: at com.android.server.wm.WallpaperWindowToken.forAllWallpaperWindows(WallpaperWindowToken.java:214)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.startWallpaperAnimations(WallpaperAnimationAdapter.java:78)
WindowManager: at com.android.server.wm.RemoteAnimationController.createWallpaperAnimations(RemoteAnimationController.java:270)
WindowManager: at com.android.server.wm.RemoteAnimationController.goodToGo(RemoteAnimationController.java:185)
WindowManager: at com.android.server.wm.AppTransition.goodToGo(AppTransition.java:419)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:277)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
starting_reveal
WindowManager: createAnimationLeash type = starting_reveal animatable = Window{f64bf2d u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.TaskOrganizerController.applyStartingWindowAnimation(TaskOrganizerController.java:634)
WindowManager: at com.android.server.wm.TaskOrganizerController.removeStartingWindow(TaskOrganizerController.java:696)
WindowManager: at com.android.server.wm.StartingSurfaceController$StartingSurface.remove(StartingSurfaceController.java:271)
WindowManager: at com.android.server.wm.ActivityRecord.lambda$removeStartingWindowAnimation$4(ActivityRecord.java:2787)
WindowManager: at com.android.server.wm.ActivityRecord.$r8$lambda$cZFIJhaFFrS84y2PDOOXTP_CRFs(Unknown Source:0)
WindowManager: at com.android.server.wm.ActivityRecord$$ExternalSyntheticLambda16.run(Unknown Source:4)
WindowManager: at com.android.server.wm.ActivityRecord.removeStartingWindowAnimation(ActivityRecord.java:2803)
WindowManager: at com.android.server.wm.ActivityRecord.removeStartingWindow(ActivityRecord.java:2732)
WindowManager: at com.android.server.wm.ActivityRecord.onFirstWindowDrawn(ActivityRecord.java:6577)
WindowManager: at com.android.server.wm.WindowState.performShowLocked(WindowState.java:4674)
WindowManager: at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:274)
WindowManager: at com.android.server.wm.DisplayContent.lambda$new$8(DisplayContent.java:1099)
WindowManager: at com.android.server.wm.DisplayContent.$r8$lambda$OtLCIQFjCt9o-SYztyeDUcWUwGs(Unknown Source:0)
WindowManager: at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda10.accept(Unknown Source:4)
WindowManager: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2684)
WindowManager: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2674)
WindowManager: at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4942)
WindowManager: at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4786)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1672)
WindowManager: at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:4946)
WindowManager: at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:1014)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:816)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
冷启动窗口
WindowManager: createAnimationLeash type = window_animation animatable = Window{4d28c0 u0 Splash Screen com.example.mysystemdialog}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5327)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5303)
WindowManager: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:652)
WindowManager: at com.android.server.wm.WindowManagerService.tryStartExitingAnimation(WindowManagerService.java:2642)
WindowManager: at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2448)
WindowManager: at com.android.server.wm.Session.relayout(Session.java:253)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:727)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
热启动窗口
WindowManager: createAnimationLeash type = window_animation animatable = Window{d22fcb2 u0 SnapshotStartingWindow for taskId=77}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5327)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5303)
WindowManager: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:652)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2593)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2487)
WindowManager: at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2053)
WindowManager: at com.android.server.wm.Session.remove(Session.java:230)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:687)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
移除动画 removeLeash
桌面
0WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x12ce9bd
0WindowManager: java.lang.Exception
0WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
0WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
0WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
0WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
0WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
0WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
0WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
0WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
0WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:307)
0WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
0WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
0WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
0WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
0WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
应用task
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x77da703
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:307)
WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
壁纸
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:322)
WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
starting_reveal
WindowManager: removeLeash leash = Surface(name=Surface(name=f64bf2d com.example.mysystemdialog/com.example.mysystemdialog.MainActivity)/@0xdf5580d - animation-leash of starting_reveal)/@0x6af05d3
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.cancelAnimation(SurfaceAnimator.java:364)
WindowManager: at com.android.server.wm.SurfaceAnimator.cancelAnimation(SurfaceAnimator.java:270)
WindowManager: at com.android.server.wm.WindowContainer.cancelAnimation(WindowContainer.java:2832)
WindowManager: at com.android.server.wm.WindowState.lambda$removeIfPossible$2(WindowState.java:2503)
WindowManager: at com.android.server.wm.WindowState.$r8$lambda$gtdPXCAzSiavwVZY5OZGcTDMs84(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowState$$ExternalSyntheticLambda0.apply(Unknown Source:2)
WindowManager: at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4942)
WindowManager: at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4786)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2501)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2487)
WindowManager: at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2053)
WindowManager: at com.android.server.wm.Session.remove(Session.java:230)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:687)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
冷启动窗口
WindowManager: removeLeash leash = Surface(name=Surface(name=4d28c0 Splash Screen com.example.mysystemdialog)/@0xbbbe9b3 - animation-leash of window_animation)/@0x7ca9ee9
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.lambda$startAnimation$0(LocalAnimationAdapter.java:67)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.$r8$lambda$gPDCFw0mQLltlXqA3mL6IUKCwLs(Unknown Source:0)
WindowManager: at com.android.server.wm.LocalAnimationAdapter$$ExternalSyntheticLambda0.run(Unknown Source:6)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
热启动窗口
WindowManager: removeLeash leash = Surface(name=Surface(name=d22fcb2 SnapshotStartingWindow for taskId=77)/@0xfcbebd0 - animation-leash of window_animation)/@0x3faeece
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.lambda$startAnimation$0(LocalAnimationAdapter.java:67)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.$r8$lambda$gPDCFw0mQLltlXqA3mL6IUKCwLs(Unknown Source:0)
WindowManager: at com.android.server.wm.LocalAnimationAdapter$$ExternalSyntheticLambda0.run(Unknown Source:6)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
小结
从当前分析以及堆栈来看,应用的启动窗口相关动画(冷启动应用主界面starting_reveal、冷启动窗口Splash Screen、热启动窗口SnapshotStartingWindow)均为本地动画,其他的动画均为远程动画。
本地动画:
窗口类型:冷启动应用主界面starting_reveal、冷启动窗口Splash Screen、热启动窗口SnapshotStartingWindow。
代码逻辑:创建动画时,从applyAnimationLocked流程到createAnimationLeash;移除动画时,从LocalAnimationAdapter的Callback到removeLeash流程。
注:starting_reveal类型动画比较特殊,涉及到StartingWindow动画流程。
远程动画:
窗口类型:桌面Task、应用Task、壁纸。
代码逻辑:创建动画时,从handleAppTransitionReady流程到createAnimationLeash;移除动画时,从IRemoteAnimationFinishedCallback流程到removeLeash流程。
动画添加流程
动画移除流程
相关文章:

Android T 远程动画显示流程(更新中)
序 本地动画和远程动画区别是什么? 本地动画:自给自足。对自身SurfaceControl矢量动画进行控制。 远程动画:拿来吧你!一个app A对另一个app B通过binder跨进程通信,控制app B的SurfaceControl矢量动画。 无论是本地动画还是远程…...

【计算机网络】【练习题及解答】【新加坡南洋理工大学】【Computer Control Network】
说明: 仅供学习使用。 一、题目描述 题目共4问,描述网络通信中的 帧传输时延(Frame Delay)、传播时延(Propagation Delay),以及 链接利用率(Link Utilization) 的相关…...

云计算HCIE备考经验分享
大家好,我是来自深圳信息职业技术学院22级鲲鹏3-1班的刘同学,在2023年9月19日成功通过了华为云计算HCIE认证,并且取得了A的成绩。下面把我的考证经验分享给大家。 转专业进鲲鹏班考HCIE 大一上学期的时候,在上Linux课程的时候&…...
Threejs API——`OrbitControls`相机控件
文章目录 API用法API OrbitControls 相机控制用法 导入import {OrbitControls } from three/examples/jsm/controls/OrbitControls.js import {DRACOLoader,AmbientLight,Color,MOUSE,...

远程教育:低代码在教育技术领域的重塑之力
新冠肺炎大流行对世界各地的行业产生了影响,其中一些行业的影响远远超过其他行业。食品、零售、供应链、娱乐和航空业是受影响最大的行业,为确保不间断运营,这引发了一场数字革命。相信,这种数字化的采用将长期保持下去࿰…...
vue 模板语法值class操作
class.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>class</title><!-- 确保引入正确的Vue版本库,下面只是示例,需要替换为实际可工作的CDN地址 --><sc…...

MySQL的原生API实现插入数据后在可视化工具上不显示的问题解决
显示表中有两行数据,该表也设置了主键和唯一索引 点进表里看却没有数据 问题原因出现在这里,虽然很多常用的数据库连接池都会开启自动提交,但ibatis的SqlSession使用sessionFactory.openSession()创建时,默认的自动提交是false&am…...

Blender教程(基础)-内插面、分离、环切、倒角-08
一、内插面 菜单位置如下图位置。 单击需要处理的面,出现一个黄色的圈。 1、菜单选中内插 鼠标悬停在黄色圈内单击左键可以来回实现内插,但是发现并不好操作。 2、快捷键内插 在选中需要操作的面之后,鼠标移动到外面,键盘在英…...

Unity 自动轮播、滑动轮播
如图所示,可设置轮播间隔,可左右滑动进行轮播 1.在UGUI创建个Image,添加自动水平组件 2.添加并配置脚本 3.代码如下,都有注释 using UnityEngine; using UnityEngine.UI;public class IndicatorManager : MonoBehaviour {public …...

纯html+js+css个人博客
首页 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8"><title>主页</title><!-- 引入layui css文件 --><link rel"stylesheet" href"layui-…...

二百二十一、HiveSQL报错:return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask
一、目的 在运行HiveSQL时,执行报错 tatement: FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask 二、在yarn上查看任务报错 The required MAP capability is more than the supported max container capability in t…...
JavaEE学习笔记 2024-1-25 --VUE的入门使用
上一篇 个人整理非商业用途,欢迎探讨与指正!! 文章目录 14.VUE基础14.1VUE的入门使用14.2条件判断14.3循环渲染14.4v-bind绑定标签属性14.5v-model表单标签的双向绑定14.6事件处理14.7axios 14.VUE基础 前端框架 UI框架:页面渲染Bootstrap,L…...
php-fpm详细讲解
PHP-FPM(FastCGI Process Manager)是PHP的一种运行模式,用于处理动态HTTP请求。 它与传统的模块式PHP(如Apache模块)相比,将PHP解析和执行过程单独封装为一个独立的进程池,通过FastCGI协议与We…...

小白水平理解面试经典题目LeetCode 455 Assign Cookies【Java实现】
455 分配cookies 小白渣翻译: 假设你是一位很棒的父母,想给你的孩子一些饼干。但是,你最多应该给每个孩子一块饼干。 每个孩子 i 都有一个贪婪因子 g[i] ,这是孩子满意的 cookie 的最小大小;每个 cookie j 都有一个…...
uniapp 问题汇总-问题数(2)
ios scroll-view无法滚动 使用uview折叠面板嵌套scroll-view 嵌套之后安卓可以滚动,ios无法滚动 <u-collapse accordion opencollapseOpen changecollapseChange ref"uCollapse" :valueuCollapseValue><u-collapse-item :nameindex :title&quo…...

[AG32VF407]国产MCU+FPGA Verilog编写控制2路gpio输出不同频率方波实验
视频讲解 [AG32VF407]国产MCUFPGA Verilog编写控制2路gpio输出不同频率方波实验 实验过程 根据原理图,选择两个pin脚作为输出 修改VE文件,clk选择PIN_OSC,使用内部晶振8Mhz,gpio使用PIN_51和52,pinout是数组 添加pll…...

python coding with ChatGPT 打卡第15天| 二叉树:翻转二叉树、对称二叉树
相关推荐 python coding with ChatGPT 打卡第12天| 二叉树:理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 文章目录 翻转二叉树Key Points相关题目视频讲解重点分析递归遍历…...

Python(19)Excel表格操作Ⅰ
目录 导包 读取EXCEL文件 1、获取worksheet名称 2、设定当前工作表 3、输出目标单元格数据 4、工作表.rows(行) 5、工作表.columns(列) 小结 导包 要想使用 python 操作 Excel 文件,应当导入 openpyxl 包。在…...

HiveSQL题——聚合函数(sum/count/max/min/avg)
目录 一、窗口函数的知识点 1.1 窗户函数的定义 1.2 窗户函数的语法 1.3 窗口函数分类 聚合函数 排序函数 前后函数 头尾函数 1.4 聚合函数 二、实际案例 2.1 每个用户累积访问次数 0 问题描述 1 数据准备 2 数据分析 3 小结 2.2 各直播间最大的同时在线人数 …...
计算机是什么做的
背景 虽然我是科班出身的,但是上大学时候,对这些内容并不感兴趣,只是简单的进行做题,考试而已。并没有思考,为啥学计算机组成原理,模电数电,微机原理,单片机,操作系统啥…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...