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
英文地址,請注明出處:http://en.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;有時比注釋更有用…