android 13 WMS/AMS系统开发-SplashScreen的添加与移除分析

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)

在这里插入图片描述

在这里插入图片描述

### 解决Spring Boot API 401 Unauthorized 认证失败 当遇到`/api/wms/receiptOrder/add-or-update`接口返回401未授权错误时,通常意味着客户端未能提供有效的身份验证凭证或权限不足。为了排查并解决问题,可以从以下几个方面入手: #### 配置安全设置 确保应用程序的安全配置正确无误。如果使用的是基于角色的访问控制(RBAC),则需确认当前用户具有执行此操作所需的适当角色。 对于Spring Security,默认情况下会保护所有端点,并要求通过HTTP Basic Auth或其他方式验证每个传入请求的身份。可以通过自定义SecurityConfig类来调整这些默认行为[^1]。 ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/**").authenticated() // 确保API路径受保护 .anyRequest().permitAll(); // 添加其他必要的配置... } } ``` #### 检查认证头 发送到服务器的每一个RESTful调用都应携带正确的认证信息。这通常是通过在HTTP头部中加入Authorization字段完成的。例如,在Postman工具里测试API时,应该指定Bearer Token作为认证机制的一部分[^2]。 ```bash curl -X POST https://example.com/api/wms/receiptOrder/add-or-update \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \ -d '{"key":"value"}' ``` #### 日志记录调试 启用详细的日志可以帮助诊断具体原因。可以在application.properties文件中增加如下属性以便获取更多关于认证过程的信息[^3]: ```properties logging.level.org.springframework.security=DEBUG ``` 这样可以查看完整的握手流程以及任何潜在异常堆栈跟踪,从而更容易定位问题所在。 #### 测试Token有效性 最后一步是验证所使用的OAuth令牌是否仍然有效且尚未过期。尝试刷新token或者重新登录以获得新的access token后再试一次请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值