Launcher启动器
Launcher(启动器、桌面) 是 Android 操作系统上用于展示应用图标、搜索应用、管理桌面快捷方式以及执行其他与设备主屏幕相关任务的用户界面。设备的主屏幕布局和外观是用户与设备交互的主要方式。
Launcher特点:
Launcher进程启动流程
SystemServer是Android系统中的一个核心进程,负责启动和初始化各种系统服务。
在SystemServer的启动过程中,会调用其他服务,如PackageManagerService(PMS)和ActivityManagerService(AMS)的初始化方法。
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启动的时候,执行startOtherServices()方法中调用了AMS的systemReady()方法,通过该方法来启动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);}
PMS服务会完成系统中应用程序的安装和管理工作。
PMS会扫描/data/app目录,加载已经安装的应用程序信息。
AMS是Android系统中负责管理应用程序生命周期和活动(Activity)状态的服务。
在AMS的初始化过程中,会注册各种系统广播接收器,包括与Launcher启动相关的广播。
4.「Launcher应用程序的注册」:
Launcher应用程序是一个特殊的系统应用,它在AndroidManifest.xml文件中配置了特定的Intent Filter,以便系统能够识别并启动它。
通常,Launcher应用程序的Action被设置为Intent.ACTION_MAIN,而Category被设置为Intent.CATEGORY_HOME。
5.「SystemReady阶段」:
当系统完成初始化并准备好启动桌面时,AMS会调用其systemReady()方法。
在systemReady()方法中,AMS会检查系统是否准备好启动Launcher,并调用相关方法来启动。
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {...synchronized (this) {...startHomeActivityLocked(currentUserId, "systemReady");...}...}
在startHomeActivityLocked()方法中,通过getHomeIntent()方法获取到要启动的HomeActivity的intent对象,mTopAction默认为INTENT.ACTION_MAIN,并添加CATEGORY_HOME的category标志。通过PackageManager去获取对应符合的Activity,获取对应的ActivityInfo,并获取对应的进程记录,此时对应的进程还没启动,为intent添加FLAG_ACTIVITY_NEW_TASK启动参数开启新栈,随后调用ActivityStartController类的startHomeActivity()方法去执行启动。
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;}
AMS启动Launcher进程。
该方法会创建一个新的进程(如果Launcher尚未运行)来启动Launcher应用程序。
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();}}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();}}
Launcher进程启动后,会向PMS请求已安装应用程序的信息,并将这些信息展示在桌面上。
用户可以通过点击桌面上的应用程序图标来启动相应的应用程序。
@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;}
InvariantDeviceProfile对象主要是存储App的基本配置信息,例如App图标的尺寸大小,文字大小,每个工作空间或文件夹能显示多少App等。
在LauncherModel的startLoader()方法中,新建了一个LoaderResults对象,通过startLoaderForResults()方法创建出一个LoaderTask的Runnable任务。
public boolean startLoader(int synchronousBindPage) {...synchronized (mLock) {// Don't bother to start the thread if we know it's not going to do anythingif (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 handlersWorker.post(r);}}
在LoaderTask的run()方法中,加载手机已安装的App的信息,查询数据库获取已安装的App的相关信息,加载Launcher布局,并将数据转化为View,绑定到界面上,最终就可以看到桌面显示的宫格列表的桌面图标了。
public void run() {...try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {// 查询数据库整理App信息,转化为View绑定到界面loadWorkspace();mResults.bindWorkspace();loadAllApps();mResults.bindAllApps();loadDeepShortcuts();mResults.bindDeepShortcuts();mBgDataModel.widgetsModel.update(mApp, null);mResults.bindWidgets();transaction.commit();} catch (CancellationException e) {// Loader stopped, ignoreTraceHelper.partitionSection(TAG, "Cancelled");}TraceHelper.endSection(TAG);}
随着Android系统的不断发展和更新,Launcher进程的启动流程也可能会发生相应的变化和优化。Android系统还支持多种启动Launcher的方式,如开机后自动启动、短按Home键启动以及异常崩溃后自动重启等。这些启动方式的实现流程也有所不同,但基本流程都与上述步骤相似。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://www.jmbhsh.com/shumazixun/35054.html