文章已同步Github博客:Launcher進程啓動
使用到的相關源碼:https://github.com/JesusYoung/AndroidResourceCode9.0/tree/master
基於Android 9.0
1、Launcher
Launcher作爲Android系統的桌面,它的作用有兩點:
- 作爲Android系統的啓動器,用於啓動應用程序;
- 作爲Android系統的桌面,用於顯示和管理應用程序的快捷圖標或者其它桌面組件;
2、Launcher進程啓動流程
2.1、SystemServer調用
在SystemServer進程啓動之後,執行其run()函數,在裏面執行了大量的配置設置操作,並且啓動了各種引導服務、核心服務以及其他服務等,包括AMS、PMS、WMS、電量管理服務等一系列服務,以及創建主線程Looper,並循環等待消息;
其中在啓動引導服務方法中,啓動了ActivityManagerService,並且在啓動其他服務的方法中,調用AMS的systemReady()方法,Launcher進程就是從這兒開始啓動的;
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);
}
2.2、AMS執行
在AMS中執行systemReady()方法,在其中執行startHomeActivityLocked()方法,傳入當前用戶ID;
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
...
synchronized (this) {
...
startHomeActivityLocked(currentUserId, "systemReady");
...
}
...
}
2.2.1、獲取Launcher的Intent
在startHomeActivityLocked()方法中,首先通過getHomeIntent()方法,獲取到要啓動的HomeActivity的intent對象,其中mTopAction默認爲INTENT.ACTION_MAIN,並添加CATEGORY_HOME的category標誌;
得到Intent對象,通過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;
}
2.2.2、啓動Launcher
在startHomeActivity()方法中,調用obtainStarter()方法獲取到一個ActivityStarter對象,setCallingUid()方法設置當前調用的Uid=0,然後執行其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默認爲false,執行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();
}
}
這裏進入了Activity的啓動流程,Launcher本身就是一個系統APP,用於顯示桌面等,LauncherApp啓動之後會執行其生命週期方法初始化桌面佈局;
2.3、初始化桌面圖標
2.3.1、執行onCreate()方法
@Override
protected void onCreate(Bundle savedInstanceState) {
...
LauncherAppState app = LauncherAppState.getInstance(this);
...
}
獲取LauncherAppState,通過LauncherAppState的getInstance()方法獲取,該方法裏面會判斷當前線程是否爲主線程,在主線程時還會直接new出對象,不在主線程時,通過MainThreadExecutor的submit()方法向主線程提交一個任務去獲取該對象;
// 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的構造方法中,會新建InvariantDeviceProfile對象,這個類主要是存儲App的基本配置信息,例如App圖標的尺寸大小,文字大小,每個工作空間或文件夾能顯示多少App等;
在LauncherAppState的構造方法中,會獲取WindowManager,並獲取屏幕的尺寸,解析桌面佈局文件,獲取默認尺寸信息等;
@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、註冊Intent廣播
新建LauncherModel對象,該對象是一個BroadcastReceiver,並添加App變化的回調,以及設置Filter並註冊廣播,用於監聽桌面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佈局
繼續回到Launcher的onCreate()方法,將Launcher添加到LauncherModel中,是以弱引用的方式添加,初始化一些其工作,解析Launcher的佈局,
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mModel = app.setLauncher(this);
...
mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
...
}
# LauncherModel
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
Preconditions.assertUIThread();
mCallbacks = new WeakReference<>(callbacks);
}
}
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()方法中,新建了一個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 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()方法中,去加載手機已安裝的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, ignore
TraceHelper.partitionSection(TAG, "Cancelled");
}
TraceHelper.endSection(TAG);
}