android 13 WMS/AMS系统开发-SplashScreen的添加与移除分析
更多内容qqun:422901085 https://ke.qq.com/course/5992266#term_id=106217431
(代码基于android-13.0.0_r6)
在系统开发过程中大家要学会怎么来学习追踪代码,这一点是非常关键的,因为在庞大系统代码中,如果什么都进行正向分析,那么很有可能因为代码过于庞大,进入分支过多而导致丢失方向,失去了主要线路,陷入一种丢了西瓜捡到芝麻情况,这情况其实经常在分析系统源码时候常见,但是这其实对我们学习主流程来说是非常不利的,因为我们往往对代码执行的主流线路都还没有摸清,没有办法对流程有一个比较好的理解,而容易被执行某个小点,小部分卡住。故经常建议大家采用如下几个方法进行:
1、首先可以尝试看需要分析流程中是否本身有相关日志开启或可以通过代码,Proto方式来开启日志,或者自己加入log,然后通过日志来大概定位流程执行
2、在第一部分已经知道了大概流程,但是还不清楚具体的过程等,这个时候就建议可以通过寻找到我们过程目标方法,就相当于以目标为参考点,然后目标方法中加入堆栈打印,或之as的debug调试,通过具体堆栈然后反向来分析流程。
下面我们就以上面的方法来试试今天的需要分析的SplashScreen
首先直观认识什么是SplashScreen,大家看如下图:
简单说就是因为首次Activity启动需要时间,一般几百ms,但是如果这个期间什么都不显示,那么给用户感觉可能有一点卡,为了更好用户体验,那么就需要点击时候立即显示,显示东西就是如上图界面,一个app图标的页面,知道app绘制完成才消失,然后显示正常的页面
好了功能知道了,我们下面就来分析吧。
分析方法步骤:
1、获取一下启动引导页面SplashScreen界面的window名字,看看是否可以从它进行入手,设置中开发者选项把动画调慢10倍,点击启动图库,同时adb shell dumpsys window windows看看对应数据:
我们挑出如下发现他就是对应的window名字
Window #9 Window{ed8162c u0 Splash Screen com.android.gallery3d}:
WindowStateAnimator{52bfa62 Splash Screen com.android.gallery3d}:
mSurface=Surface(name=Splash Screen com.android.gallery3d)/@0x3cfa7f3
imeLayeringTarget in display# 0 Window{ed8162c u0 Splash Screen com.android.gallery3d}
知道window名字后我们开启去代码搜索谁创建的?
test@test:~/aosp/frameworks/base$ grep "Splash Screen" ./ -rn
./core/java/android/window/SplashScreenView.java:638: * Get the view containing the Splash Screen icon and its background.
./libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java:311: params.setTitle("Splash Screen " + activityInfo.packageName);
./libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java:45: // Starting Windows (Splash Screen)
从结果可以看出,明显是./libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java:311:
这里我们既可以去看一下StartingSurfaceDrawer代码,然后从它的代码开始入手分析
2、知道代码对应地方,可以尝试用日志打印堆栈方法来定位系统调用流程
代码中可以简单看出是addStartingWindow中的调用的,即只要关心addStartingWindow
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
mSplashScreenExecutor.execute(() -> {
//省略
if (isSplashScreenType(suggestionType)) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
//省略
});
}
通过堆栈发现addStartingWindow如下,而且知道资格进程运行在systemui进程(log中有进程好既可以判断):
addStartingWindow:124, StartingWindowController (com.android.wm.shell.startingsurface)
addStartingWindow:392, ShellTaskOrganizer (com.android.wm.shell)
lambda$addStartingWindow$0$android-window-TaskOrganizer$1:286, TaskOrganizer$1 (android.window)
run:-1, TaskOrganizer$1$$ExternalSyntheticLambda5 (android.window)
handleCallback:942, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
main:7898, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:936, ZygoteInit (com.android.internal.os)
可以看出其实是TaskOrganizer类中进行调用
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
@Override
public void addStartingWindow(StartingWindowInfo windowInfo,
IBinder appToken) {
mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
}
//省略
这里其实就是一个跨进程调用,调用方法是addStartingWindow,那么就可以去framework下搜索:
排除一些Test就如下几个地方
test@test:~/aosp/frameworks/base$ grep "\.addStartingWindow(" ./ -rn
./services/core/java/com/android/server/wm/StartingSurfaceController.java:85: if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(
./services/core/java/com/android/server/wm/StartingSurfaceController.java:169: mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
./services/core/java/com/android/server/wm/TaskOrganizerController.java:510: lastOrganizer.addStartingWindow(info, activity.token);
明显看出其实最后都是调用了TaskOrganizerController的addStartingWindow方法:
boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
TaskSnapshot taskSnapshot) {
//ignore
try {
lastOrganizer.addStartingWindow(info, activity.token);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskStart callback", e);
return false;
}
return true;
}
又可以在这里进行堆栈打印追踪:
addStartingWindow:510, TaskOrganizerController (com.android.server.wm)
createSplashScreenStartingSurface:85, StartingSurfaceController (com.android.server.wm)
createStartingSurface:36, SplashScreenStartingData (com.android.server.wm)
run:2418, ActivityRecord$AddStartingWindow (com.android.server.wm)
scheduleAddStartingWindow:2391, ActivityRecord (com.android.server.wm)
addStartingWindow:2370, ActivityRecord (com.android.server.wm)
showStartingWindow:6978, ActivityRecord (com.android.server.wm)
showStartingWindow:6938, ActivityRecord (com.android.server.wm)
showStartingWindow:197, StartingSurfaceController (com.android.server.wm)
startActivityLocked:5150, Task (com.android.server.wm)
startActivityInner:1905, ActivityStarter (com.android.server.wm)
startActivityUnchecked:1661, ActivityStarter (com.android.server.wm)
executeRequest:1216, ActivityStarter (com.android.server.wm)
execute:702, ActivityStarter (com.android.server.wm)
startActivityAsUser:1240, ActivityTaskManagerService (com.android.server.wm)
startActivityAsUser:1203, ActivityTaskManagerService (com.android.server.wm)
startActivity:1178, ActivityTaskManagerService (com.android.server.wm)
onTransact:893, IActivityTaskManager$Stub (android.app)
onTransact:5183, ActivityTaskManagerService (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)