Android開發(fā)Launcher進(jìn)程啟動(dòng)流程
1、Launcher
Launcher作為Android系統(tǒng)的桌面,它的作用有兩點(diǎn):
作為Android系統(tǒng)的啟動(dòng)器,用于啟動(dòng)應(yīng)用程序;
作為Android系統(tǒng)的桌面,用于顯示和管理應(yīng)用程序的快捷圖標(biāo)或者其它桌面組件;
2、Launcher進(jìn)程啟動(dòng)流程
2.1、SystemServer調(diào)用
在SystemServer進(jìn)程啟動(dòng)之后,執(zhí)行其run()函數(shù),在里面執(zhí)行了大量的配置設(shè)置操作,并且啟動(dòng)了各種引導(dǎo)服務(wù)、核心服務(wù)以及其他服務(wù)等,包括AMS、PMS、WMS、電量管理服務(wù)等一系列服務(wù),以及創(chuàng)建主線程Looper,并循環(huán)等待消息;
其中在啟動(dòng)引導(dǎo)服務(wù)方法中,啟動(dòng)了ActivityManagerService,并且在啟動(dòng)其他服務(wù)的方法中,調(diào)用AMS的systemReady()方法,Launcher進(jìn)程就是從這兒開始啟動(dòng)的;
public final class SystemServer { private void run() { ... startBootstrapServices(); startOtherServices(); ... } private void startBootstrapServices() { ... mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); ... } private void startOtherServices() { ... mActivityManagerService.systemReady(() -> { }, BOOT_TIMINGS_TRACE_LOG); } }
在SystemServer啟動(dòng)的時(shí)候,執(zhí)行startOtherServices()方法中,里面調(diào)用了AMS的systemReady()方法,通過該方法來啟動(dòng)Launcher;
// Tag for timing measurement of main thread. private static final String SYSTEM_SERVER_TIMING_TAG = "SystemServerTiming"; private static final TimingsTraceLog BOOT_TIMINGS_TRACE_LOG = new TimingsTraceLog(SYSTEM_SERVER_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); private void startOtherServices() { ... mActivityManagerService.systemReady(() -> { Slog.i(TAG, "Making services ready"); traceBeginAndSlog("StartActivityManagerReadyPhase"); mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY); ... }, BOOT_TIMINGS_TRACE_LOG); }
2.2、AMS執(zhí)行
在AMS中執(zhí)行systemReady()方法,在其中執(zhí)行startHomeActivityLocked()方法,傳入當(dāng)前用戶ID;
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) { ... synchronized (this) { ... startHomeActivityLocked(currentUserId, "systemReady"); ... } ... }
2.2.1、獲取Launcher的Intent
在startHomeActivityLocked()方法中,首先通過getHomeIntent()方法,獲取到要啟動(dòng)的HomeActivity的intent對(duì)象,其中mTopAction默認(rèn)為INTENT.ACTION_MAIN,并添加CATEGORY_HOME的category標(biāo)志;
得到Intent對(duì)象,通過PackageManager去獲取對(duì)應(yīng)符合的Activity,獲取對(duì)應(yīng)的ActivityInfo,并獲取對(duì)應(yīng)的進(jìn)程記錄,此時(shí)對(duì)應(yīng)的進(jìn)程還沒啟動(dòng),后面繼續(xù)執(zhí)行,為intent添加FLAG_ACTIVITY_NEW_TASK啟動(dòng)參數(shù),開啟新棧,隨后調(diào)用ActivityStartController類的startHomeActivity()方法去執(zhí)行啟動(dòng);
boolean startHomeActivityLocked(int userId, String reason) { ... Intent intent = getHomeIntent(); ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); if (aInfo != null) { intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being instrumented. aInfo = new ActivityInfo(aInfo); aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); ProcessRecord app = getProcessRecordLocked(aInfo.processName, aInfo.applicationInfo.uid, true); if (app == null || app.instr == null) { intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK); final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); // For ANR debugging to verify if the user activity is the one that actually launched. final String myReason = reason + ":" + userId + ":" + resolvedUserId; mActivityStartController.startHomeActivity(intent, aInfo, myReason); } } ... return true; } Intent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); } return intent; }
2.2.2、啟動(dòng)Launcher
在startHomeActivity()方法中,調(diào)用obtainStarter()方法獲取到一個(gè)ActivityStarter對(duì)象,setCallingUid()方法設(shè)置當(dāng)前調(diào)用的Uid=0,然后執(zhí)行其execute()方法;
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(reason); mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) .setCallingUid(0) .setActivityInfo(aInfo) .execute(); mLastHomeActivityStartRecord = tmpOutRecord[0]; if (mSupervisor.inResumeTopActivity) { // If we are in resume section already, home activity will be initialized, but not // resumed (to avoid recursive resume) and will stay that way until something pokes it // again. We need to schedule another resume. mSupervisor.scheduleResumeTopActivities(); } }
在ActivityStarter的execute()方法中,mayWait默認(rèn)為false,執(zhí)行startActivity()方法;
int execute() { try { // TODO(b/64750076): Look into passing request directly to these methods to allow // for transactional diffs and preprocessing. if (mRequest.mayWait) { return startActivityMayWait(mRequest.caller, mRequest.callingUid, ...); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, ...); } } finally { onExecutionComplete(); } }
這里進(jìn)入了Activity的啟動(dòng)流程,Launcher本身就是一個(gè)系統(tǒng)APP,用于顯示桌面等,LauncherApp啟動(dòng)之后會(huì)執(zhí)行其生命周期方法初始化桌面布局;
2.3、初始化桌面圖標(biāo)
2.3.1、執(zhí)行onCreate()方法
@Override protected void onCreate(Bundle savedInstanceState) { ... LauncherAppState app = LauncherAppState.getInstance(this); ... }
獲取LauncherAppState,通過LauncherAppState的getInstance()方法獲取,該方法里面會(huì)判斷當(dāng)前線程是否為主線程,在主線程時(shí)還會(huì)直接new出對(duì)象,不在主線程時(shí),通過MainThreadExecutor的submit()方法向主線程提交一個(gè)任務(wù)去獲取該對(duì)象;
// We do not need any synchronization for this variable as its only written on UI thread. private static LauncherAppState INSTANCE; public static LauncherAppState getInstance(final Context context) { if (INSTANCE == null) { if (Looper.myLooper() == Looper.getMainLooper()) { INSTANCE = new LauncherAppState(context.getApplicationContext()); } else { try { return new MainThreadExecutor().submit(new Callable<LauncherAppState>() { @Override public LauncherAppState call() throws Exception { return LauncherAppState.getInstance(context); } }).get(); } catch (InterruptedException|ExecutionException e) { throw new RuntimeException(e); } } } return INSTANCE; }
2.3.2、讀取安裝APP信息
在LauncherAppState的構(gòu)造方法中,會(huì)新建InvariantDeviceProfile對(duì)象,這個(gè)類主要是存儲(chǔ)App的基本配置信息,例如App圖標(biāo)的尺寸大小,文字大小,每個(gè)工作空間或文件夾能顯示多少App等;
在LauncherAppState的構(gòu)造方法中,會(huì)獲取WindowManager,并獲取屏幕的尺寸,解析桌面布局文件,獲取默認(rèn)尺寸信息等;
@TargetApi(23) public InvariantDeviceProfile(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); display.getMetrics(dm); ... ArrayList<InvariantDeviceProfile> closestProfiles = findClosestDeviceProfiles(minWidthDps, minHeightDps, getPredefinedDeviceProfiles(context)); ... } ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) { ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>(); try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if ((type == XmlPullParser.START_TAG) && "profile".equals(parser.getName())) { TypedArray a = context.obtainStyledAttributes(Xml.asAttributeSet(parser), R.styleable.InvariantDeviceProfile); int numRows = a.getInt(R.styleable.InvariantDeviceProfile_numRows, 0); int numColumns = a.getInt(R.styleable.InvariantDeviceProfile_numColumns, 0); float iconSize = a.getFloat(R.styleable.InvariantDeviceProfile_iconSize, 0); profiles.add(new InvariantDeviceProfile( a.getString(R.styleable.InvariantDeviceProfile_name), a.getFloat(R.styleable.InvariantDeviceProfile_minWidthDps, 0), a.getFloat(R.styleable.InvariantDeviceProfile_minHeightDps, 0), numRows, numColumns, a.getInt(R.styleable.InvariantDeviceProfile_numFolderRows, numRows), a.getInt(R.styleable.InvariantDeviceProfile_numFolderColumns, numColumns), iconSize, a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize), a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0), a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns), a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0), a.getResourceId(R.styleable.InvariantDeviceProfile_demoModeLayoutId, 0))); a.recycle(); } } } catch (IOException|XmlPullParserException e) { throw new RuntimeException(e); } return profiles; }
2.3.3、注冊(cè)Intent廣播
新建LauncherModel對(duì)象,該對(duì)象是一個(gè)BroadcastReceiver,并添加App變化的回調(diào),以及設(shè)置Filter并注冊(cè)廣播,用于監(jiān)聽桌面App的變化;
private LauncherAppState(Context context) { ... mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); // Register intent receivers IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); // For handling managed profiles filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); ... mContext.registerReceiver(mModel, filter); ... } public class LauncherModel extends BroadcastReceiver ... {}
2.3.4、解析Launcher布局
繼續(xù)回到Launcher的onCreate()方法,將Launcher添加到LauncherModel中,是以弱引用的方式添加,初始化一些其工作,解析Launcher的布局,
2.3.5、加載桌面
onCreate()方法中,通過LauncherModel的startLoader()來加載桌面App;
@Override protected void onCreate(Bundle savedInstanceState) { ... if (!mModel.startLoader(currentScreen)) { if (!internalStateHandled) { // If we are not binding synchronously, show a fade in animation when // the first page bind completes. mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0); } } else { // Pages bound synchronously. mWorkspace.setCurrentPage(currentScreen); setWorkspaceLoading(true); } ... }
在LauncherModel的startLoader()方法中,新建了一個(gè)LoaderResults對(duì)象,并通過startLoaderForResults()方法創(chuàng)建出一個(gè)LoaderTask的Runnable任務(wù),將其在工作線程中執(zhí)行起來;
public boolean startLoader(int synchronousBindPage) { ... synchronized (mLock) { // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { ... LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel, mBgAllAppsList, synchronousBindPage, mCallbacks); if (mModelLoaded && !mIsLoaderTaskRunning) { ... return true; } else { startLoaderForResults(loaderResults); } } } return false; } public void startLoaderForResults(LoaderResults results) { synchronized (mLock) { stopLoader(); mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); runOnWorkerThread(mLoaderTask); } } private static void runOnWorkerThread(Runnable r) { if (sWorkerThread.getThreadId() == Process.myTid()) { r.run(); } else { // If we are not on the worker thread, then post to the worker handler sWorker.post(r); } }
在LoaderTask的run()方法中,去加載手機(jī)已安裝的App的信息,查詢數(shù)據(jù)庫(kù)獲取已安裝的App的相關(guān)信息,加載Launcher布局,并將數(shù)據(jù)轉(zhuǎn)化為View,綁定到界面上,由此我們就可以看到桌面顯示的宮格列表的桌面圖標(biāo)了;
public void run() { ... try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { // 查詢數(shù)據(jù)庫(kù)整理App信息,轉(zhuǎn)化為View綁定到界面 loadWorkspace(); mResults.bindWorkspace(); loadAllApps(); mResults.bindAllApps(); loadDeepShortcuts(); mResults.bindDeepShortcuts(); mBgDataModel.widgetsModel.update(mApp, null); mResults.bindWidgets(); transaction.commit(); } catch (CancellationException e) { // Loader stopped, ignore TraceHelper.partitionSection(TAG, "Cancelled"); } TraceHelper.endSection(TAG); }
以上就是Android開發(fā)Launcher進(jìn)程啟動(dòng)流程的詳細(xì)內(nèi)容,更多關(guān)于Android Launcher啟動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android逐幀動(dòng)畫實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android逐幀動(dòng)畫實(shí)現(xiàn)代碼,可以通過xml或java代碼實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01- 這篇文章主要為大家詳細(xì)介紹了Android中Handler機(jī)制的使用,文中的示例代碼講解詳細(xì),有需要的朋友可以借鑒參考下,希望能夠?qū)Υ蠹矣兴鶐椭?/div> 2022-11-11
藍(lán)牙原理Android代碼實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了藍(lán)牙原理Android代碼實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09利用Flutter實(shí)現(xiàn)背景圖片毛玻璃效果實(shí)例
Flutter沒有單獨(dú)的模糊處理容器,需要部件層層疊加實(shí)現(xiàn)模糊效果,下面這篇文章主要給大家介紹了關(guān)于利用Flutter實(shí)現(xiàn)背景圖片毛玻璃效果的相關(guān)資料,需要的朋友可以參考下2022-06-06kotlin中的數(shù)據(jù)轉(zhuǎn)換方法(示例詳解)
這篇文章介紹了Kotlin中將數(shù)字轉(zhuǎn)換為字符串和字符串轉(zhuǎn)換為數(shù)字的多種方法,包括使用`toString()`、字符串模板、格式化字符串、處理可空類型等,同時(shí),也詳細(xì)講解了如何安全地進(jìn)行字符串到數(shù)字的轉(zhuǎn)換,并處理了不同進(jìn)制和本地化格式的字符串轉(zhuǎn)換,感興趣的朋友一起看看吧2025-03-03最新評(píng)論