Android 16系统源码_SplashScreen窗口的创建流程(一)

一 点击桌面图标触发SplashScreen

1.1 点击桌面图标打开应用

点击桌面的短信图标,然后打开短信页面,使用winscope获取数据。
winscope得到的数据
从点击短信图标到应用内容完全展开,中间有出现一个标题带有“Splash Screen”字符串的窗口。

二 Splash Screen窗口创建的源码调用流程

在aosp14源码中搜索Splash Screen关键字,可以发现SplashscreenContentDrawer.java这个类有创建这个标题的窗口对象。

//frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
public class SplashscreenContentDrawer {static WindowManager.LayoutParams createLayoutParameters(Context context,StartingWindowInfo windowInfo,@StartingWindowInfo.StartingWindowType int suggestType,CharSequence title, int pixelFormat, IBinder appToken) {final WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); ...代码省略...          windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;params.flags = windowFlags;params.token = appToken;params.packageName = activityInfo.packageName;params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;//关键字params.setTitle("Splash Screen " + title);return params;}
}

在源码中查看调用,发现SplashscreenWindowCreator这个类的addSplashScreenStartingWindow方法有调用TaskSnapshotWindow的createLayoutParameters方法。
find usages结果
持续在源码中搜索查找,最终发现Splash Screen窗口的创建源码调用流程主要分为两个阶段,分别是SystemServer阶段和SystemUI阶段。

2.1 SystemUI阶段

由于SplashScreen窗口的创建是在SystemUI进程,所以我们先来看下SystemUI进程相关方法源码的调用流程。

//frameworks/base/core/java/android/window/TaskOrganizer.java
public class TaskOrganizer extends WindowOrganizer {private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {@Overridepublic void addStartingWindow(StartingWindowInfo windowInfo) {//调用ShellTaskOrganizer的addStartingWindow方法mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo));}}
}
//frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
public class ShellTaskOrganizer extends TaskOrganizer implementsCompatUIController.CompatUICallback { private StartingWindowController mStartingWindow;@Overridepublic void addStartingWindow(StartingWindowInfo info) {if (mStartingWindow != null) {//调用StartingWindowController的addStartingWindow方法mStartingWindow.addStartingWindow(info);}}
}
//frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
public class StartingWindowController implements RemoteCallable<StartingWindowController> {private final StartingSurfaceDrawer mStartingSurfaceDrawer;public void addStartingWindow(StartingWindowInfo windowInfo) {mSplashScreenExecutor.execute(() -> {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addStartingWindow");final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType(windowInfo);final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;if (suggestionType == STARTING_WINDOW_TYPE_WINDOWLESS) {mStartingSurfaceDrawer.addWindowlessStartingSurface(windowInfo);} else if (isSplashScreenType(suggestionType)) {//调用StartingSurfaceDrawer的addSplashScreenStartingWindow方法mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, suggestionType);} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {final TaskSnapshot snapshot = windowInfo.taskSnapshot;mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, snapshot);}...代码省略...Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);});}
}//frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
public class StartingSurfaceDrawer {private final SnapshotWindowCreator mSnapshotWindowCreator;void addSplashScreenStartingWindow(StartingWindowInfo windowInfo,@StartingWindowInfo.StartingWindowType int suggestType) {...代码省略...//调用SplashscreenContentDrawer的createLayoutParameters方法final WindowManager.LayoutParams params = SplashscreenContentDrawer.createLayoutParameters(context, windowInfo, suggestType, activityInfo.packageName,suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT, windowInfo.appToken);}
}
//frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
public class SplashscreenContentDrawer {static WindowManager.LayoutParams createLayoutParameters(Context context,StartingWindowInfo windowInfo,@StartingWindowInfo.StartingWindowType int suggestType,CharSequence title, int pixelFormat, IBinder appToken) {final WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); ...代码省略...          windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;params.flags = windowFlags;params.token = appToken;params.packageName = activityInfo.packageName;params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;//关键字params.setTitle("Splash Screen " + title);return params;}
}

2.2 SystemUI阶段源码调用流程图

SystemUI阶段
TaskOrganizer内部类ITaskOrganizer对象的addStartingWindow方法是被SystemServer跨进程调用的。

2.3 SystemServer阶段源码调用流程图

通过对systemServer进程断点调试,可以得到如下堆栈信息。堆栈信息

public class ActivityTaskManagerService extends IActivityTaskManager.Stub {private int startActivityAsUser(IApplicationThread caller, String callingPackage,@Nullable String callingFeatureId, Intent intent, String resolvedType,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {...代码省略...return getActivityStartController().obtainStarter(intent, "startActivityAsUser").setCaller(caller).setCallingPackage(callingPackage).setCallingFeatureId(callingFeatureId).setResolvedType(resolvedType).setResultTo(resultTo).setResultWho(resultWho).setRequestCode(requestCode).setStartFlags(startFlags).setProfilerInfo(profilerInfo).setActivityOptions(opts).setUserId(userId).execute();}
}
class ActivityStarter {int execute() {...代码省略...res = executeRequest(mRequest);...代码省略...      }private int executeRequest(Request request) {...代码省略...mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, checkedOptions,inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid); ...代码省略...                     }private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, ActivityOptions options, Task inTask,TaskFragment inTaskFragment,BalVerdict balVerdict,NeededUriGrants intentGrants, int realCallingUid) {...代码省略...     result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, options, inTask, inTaskFragment, balVerdict,intentGrants, realCallingUid);...代码省略...                             }private Task mTargetRootTask;int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, ActivityOptions options, Task inTask,TaskFragment inTaskFragment, BalVerdict balVerdict,NeededUriGrants intentGrants, int realCallingUid) {...代码省略...               mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch, mOptions, sourceRecord);     ...代码省略...                }
}class Task extends TaskFragment {void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {...代码省略...      if (r.mLaunchTaskBehind) {// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we// tell WindowManager that r is visible even though it is at the back of the root// task.r.setVisibility(true);ensureActivitiesVisible(null /* starting */);// If launching behind, the app will start regardless of what's above it, so mark it// as unknown even before prior `pause`. This also prevents a race between set-ready// and activityPause. Launch-behind is basically only used for dream now.if (!r.isVisibleRequested()) {r.notifyUnknownVisibilityLaunchedForKeyguardTransition();}// Go ahead to execute app transition for this activity since the app transition// will not be triggered through the resume channel.mDisplayContent.executeAppTransition();} else if (SHOW_APP_STARTING_PREVIEW && doShow) {// Figure out if we are transitioning from another activity that is// "has the same starting icon" as the next one.  This allows the// window manager to keep the previous window it had previously// created, if it still had one.Task baseTask = r.getTask();final ActivityRecord prev = baseTask.getActivity(a -> a.mStartingData != null && a.showToCurrentUser());//调用ActivityRecord的showStartingWindow方法mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,isTaskSwitch, sourceRecord);}         }
}final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,boolean processRunning, boolean startActivity, ActivityRecord sourceRecord,ActivityOptions candidateOptions) {...代码省略...final boolean scheduled = addStartingWindow(packageName, resolvedTheme,prev, newTask || newSingleActivity, taskSwitch, processRunning,allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn);...代码省略...} boolean addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask,boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot,boolean activityCreated, boolean isSimple,boolean activityAllDrawn) {...代码省略...ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");mStartingData = new SplashScreenStartingData(mWmService, resolvedTheme, typeParameter);scheduleAddStartingWindow();return true;}private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();void scheduleAddStartingWindow() {//调用AddStartingWindow的run方法mAddStartingWindow.run();}private class AddStartingWindow implements Runnable {@Overridepublic void run() {final StartingData startingData;...代码省略...surface = startingData.createStartingSurface(ActivityRecord.this);...代码省略...		 	}
}
//frameworks/base/services/core/java/com/android/server/wm/SplashScreenStartingData.java
class SplashScreenStartingData extends StartingData {//父类StartingData的属性protected final WindowManagerService mService;@OverrideStartingSurface createStartingSurface(ActivityRecord activity) {//调用StartingSurfaceController的createSplashScreenStartingSurface方法return mService.mStartingSurfaceController.createSplashScreenStartingSurface(activity, mTheme);}
}//frameworks/base/services/core/java/com/android/server/wm/StartingSurfaceController.java
public class StartingSurfaceController {StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, int theme) {synchronized (mService.mGlobalLock) {final Task task = activity.getTask();final TaskOrganizerController controller =mService.mAtmService.mTaskOrganizerController;//调用TaskOrganizerController的addStartingWindow方法if (task != null && controller.addStartingWindow(task, activity, theme,null /* taskSnapshot */)) {return new StartingSurface(task, controller.getTaskOrganizer());}}return null;}
}
//frameworks/base/services/core/java/com/android/server/wm/TaskOrganizerController.java
class TaskOrganizerController extends ITaskOrganizerController.Stub {boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme,TaskSnapshot taskSnapshot) {final Task rootTask = task.getRootTask();if (rootTask == null || activity.mStartingData == null) {return false;}final ITaskOrganizer lastOrganizer = getTaskOrganizer();if (lastOrganizer == null) {return false;}final StartingWindowInfo info = task.getStartingWindowInfo(activity);if (launchTheme != 0) {info.splashScreenThemeResId = launchTheme;}info.taskSnapshot = taskSnapshot;info.appToken = activity.token;// make this happen prior than prepare surfacetry {//调用ITaskOrganizer的addStartingWindow方法 lastOrganizer.addStartingWindow(info);} catch (RemoteException e) {Slog.e(TAG, "Exception sending onTaskStart callback", e);return false;}return true;}
}

2.4 SystemServer阶段源码调用流程图

SystemServer阶段

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88748.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性代数学习笔记

矩阵 矩阵是一种非常重要的数学对象,它通常由一个由数字排成的矩形阵列来定义。一个矩阵由若干行和若干列组成,被称为矩阵的行数和列数。一般情况下,矩阵的行数和列数分别用 n n n 和 m m m 表示。<

2025.7.13总结

每次写日记&#xff0c;总觉得自我感受不是很好&#xff0c;脑子总会有许多消极思想。在网上&#xff0c;我曾看到一个关于“人生是一场巨大的事与愿违”&#xff0c;可能&#xff0c;真的是这个样子吧。以前的我&#xff0c;有上进心&#xff0c;有目标感&#xff0c;脚踏实地…

linux-网络-网络管理发展历程

Linux 的网络管理机制经历了多个阶段的发展&#xff0c;从早期的静态配置到现代动态管理工具的出现&#xff0c;反映了 Linux 系统在网络连接、自动化和用户体验方面的不断演进。以下是 Linux 网络管理发展的主要阶段&#xff1a;1. 早期的静态网络配置&#xff08;传统方式&am…

华为 GaussDB :技术特性、应用局限与市场争议

3-5月间&#xff0c;老夫在某学校带了这门课&#xff0c;简单总结一下课程外的看法&#xff1a;华为 GaussDB 作为华为云生态中的核心数据库产品&#xff0c;自推出以来便承载着华为在数据基础设施领域的战略野心。其技术路线既延续了开源数据库的兼容性优势&#xff0c;又深度…

从零开始学习深度学习—水果分类之PyQt5App

一、项目背景⭐&#xff1a;本项目是“从零开始学习深度学习”系列中的第二个实战项目&#xff0c;旨在实现第一个简易App(图像分类任务——水果分类)&#xff0c;进一步地落地AI模型应用&#xff0c;帮助初学者初步了解模型落地。基于PyQt5图形界面的水果图像分类系统&#xf…

小架构step系列13:测试用例的加载

1 概述测试用例的编写要有一些基础的规范&#xff0c;在本文先定义文件名称和测试用例方法名的规范。2 文件加载原理先从源码来看一下测试用例的文件加载原理。2.1 文件的匹配主要是通过注解来扫描测试用例。// 在IDEA测试用例启动时&#xff0c;调用junit-platform-launcher-x…

K8S的CNI之calico插件升级至3.30.2

前言宿主机ping不通K8S的pod&#xff0c;一直存在丢包的现象&#xff0c;排查了防火墙、日志、详细信息等没发现什么问题&#xff0c;最后搜索发现&#xff0c;是因为把K8S的版本升级之后&#xff0c;旧版本的CNI插件不适配原因导致的&#xff0c;于是就把calico也一并升级并且…

Spring Boot RESTful API 设计指南:查询接口规范与最佳实践

Spring Boot RESTful API 设计指南&#xff1a;查询接口规范与最佳实践 引言 在 Spring Boot 开发中&#xff0c;查询接口的设计直接影响着系统的可用性、可维护性和性能。本文将深入探讨如何规范设计查询接口&#xff0c;包括 GET/POST 的选择、参数定义、校验规则等&#xff…

ctfshow萌新题集

记录一下前半部分是能自己写出来的&#xff0c;后半部分是需要提示的&#xff0c;感觉自己归来两年仍是萌新 misc部分 知识点 base家族密文特征 Base16 (Hex) 字符集&#xff1a;0-9, A-F&#xff08;不区分大小写&#xff09;。特征&#xff1a; 长度是 2 的倍数&#xff…

2025年语言处理、大数据与人机交互国际会议(DHCI 2025)

&#x1f310;&#x1f916;&#x1f9e0; 语言处理、大数据与人机交互&#xff1a;探索智能未来 —— DHCI 2025国际会议2025年语言处理、大数据与人机交互国际会议&#xff08;DHCI 2025&#xff09; 将于2025年在中国重庆市召开。这次盛会将汇聚全球顶尖专家、学者及行业领袖…

RIP实验以及核心原理

RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种内部网关协议&#xff0c;基于距离矢量算法&#xff0c;用于在自治系统内交换路由信息。RIP 核心原理距离矢量算法&#xff1a;RIP 使用跳数作为路径选择的唯一度量标准。每经过一个路由…

基于大数据的电力系统故障诊断技术研究

摘要本文提出了一种创新性的基于大数据技术的电力系统故障诊断方法&#xff0c;该方法通过整合先进的机器学习算法和交互式可视化技术&#xff0c;实现了对电力系统各类故障的智能化识别与深度分析。该系统采用随机森林算法作为核心分类器&#xff0c;构建了高精度的故障分类模…

MySQL 分区功能应用专门实现全方位详解与示例

MySQL 分区功能允许将表的数据分散存储在不同的物理分区中,同时保持逻辑上的单一表结构。下面我将从基础概念到高级应用,全面讲解 MySQL 分区实现。 一、分区核心作用 1. 性能提升 分区剪枝(Partition Pruning):查询时自动跳过不相关的分区,减少数据扫描量 并行处理:不…

汽车功能安全-嵌入式软件测试(软件合格性测试)【目的、验证输入、集成验证要求】11

文章目录1 嵌入式软件测试&#xff08;Testing of the embedded Software&#xff09;2 测试输入3 验证要求和建议3.1 测试环境3.2 测试方法3.2.1 基于需求的测试3.2.2 故障注入测试3.2.3 两种方法的区别与联系总结3.3 测试用例导出方法4 嵌入式软件的测试结果评价5 测试输出物…

【webrtc】gcc当前可用码率1:怎么决策的

【webrtc】当前最大码率是怎么决策的1 看日志,跟踪代码最大码率 是probe的上限 默认值很大 外部设置的较小,调用堆栈 无限大作为默认值 默认是无限大,所以使用预设值 【webrtc】码率设定中的 int64_t 的无限大

UE5 C++计时器

UE5 C计时器 计时器一&#xff1a; .h文件 FTimerHandle TimerHandle_BetweenShot;//定义时间句柄 void StartFire();void EndFire();.cpp文件 #include “TimerManager.h” void ASpaceShip::StartFire() {GetWorldTimerManager().SetTimer(TimerHandle_BetweenShot, this, &a…

【hivesql 已知维度父子关系加工层级表】

这里写自定义目录标题1. 维度表示例1.1清单表1.2层级表2.从清单表加工层级表2.1 注意点2.2 加工方式&#xff08;join&#xff09;2.3 使用函数3.清单表字段加工3.1通过上级编码信息加工级别信息3.2 通过级别信息&#xff0c;加工上级编码信息4.创建维度表的一般注意点1. 维度表…

Ubuntu重装系统后ssh连接不上(遇到 ​​“Unit ssh.service not found“​​ 错误)

重装系统时不知道为什么SSH 服务未安装&#xff0c;以下是解决方案&#xff1a;先检查ssh服务安装没安装 sudo systemctl status ssh # Ubuntu/Debian如果 systemctl 找不到服务&#xff0c;可能是 SSH 未安装&#xff1a;sudo apt update sudo apt install openssh-serve…

2025社交电商新风口:推客小程序的商业逻辑与技术实现

一、推客小程序市场前景与商业价值在当今社交电商蓬勃发展的时代&#xff0c;推客小程序已成为连接商家与消费者的重要桥梁。推客模式结合了社交传播与电商变现的双重优势&#xff0c;通过用户自发分享带来裂变式增长&#xff0c;为商家创造了全新的营销渠道。推客小程序的核心…

Go 单元测试进阶:AI 加持下的高效实践与避坑指南

单元测试的必要性与基础单元测试不仅是保障代码质量的手段&#xff0c;也是优秀的设计工具和文档形式&#xff0c;对软件开发具有重要意义。另一种形式的文档&#xff1a;好的单元测试是一种活文档&#xff0c;能清晰展示代码单元的预期用途和行为&#xff0c;有时比注释更有用…