本系列主要介紹Android8.0系統啓動過程當中涉及到的init、Zygote、SystemServer和Launcher。 在以前的三篇文章中,講解了以下的過程:java
在完成以上三個過程後,咱們的系統就開始加載Launcher應用,查看源碼能夠發現Launcher是做爲一個APP應用執行的,其通常位於系統的packages/apps目錄下,能夠經過該應用啓動系統中其餘應用程序,提供快捷訪問圖標。android
在SystemServer啓動時,會先啓動引導服務,其中包括PMS(PackageManagerService)和AMS(ActivityManagerService),其中PMS主要做用是系統中的APK的解析和安裝;AMS主要用於四大組件的啓動 和管理,所以LauncherActivity經過AMS啓動。 完成引導服務的啓動後,開啓啓動其餘服務。啓動Launcher的入口爲AMS的systemReady方法,promise
frameworks\base\services\java\com\android\server\SystemServer.java
private void startOtherServices() {
...
//在此以前會作大量的準備工做,包括AMS、PMS 和NetworkScoreService等各類服務,完成以上操做後,表示activity manager能夠運行
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
traceBeginAndSlog("StartActivityManagerReadyPhase");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
...
}
...
...
}
複製代碼
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
traceLog.traceBegin("PhaseActivityManagerReady");
synchronized(this) {
...
mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
...
}
}
複製代碼
AMS經過調用ActivityStack實現對堆棧中Activity對象的管理,咱們的最終目的是查找到Launcher應用所在的Activity是如何被調用起來的? 其流程以下: ActivityStackSuperior#resumeFocusedStackTopActivityLocked() ->ActivityStack#resumeTopActivityUncheckedLocked()->resumeTopActivityInnerLocked() 在resumeTopActivityInnerLocked中,經過調用startHomeActivityLocked方法,開啓啓動Launcher的Activty。緩存
frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
...
return false;
複製代碼
frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
return false;
}
boolean result = false;
try {
mStackSupervisor.inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
return result;
}
複製代碼
frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(prev, reason);
...
if (r != null && !r.finishing) {
moveFocusableActivityStackToFrontLocked(r, myReason);
return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser, myReason);
...
}
複製代碼
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
boolean startHomeActivityLocked(int userId, String reason) {
//1 判斷工廠模式和topAction
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
return false;
}
//2 建立啓動Launcher的Intent
Intent intent = getHomeIntent();
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
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() | Intent.FLAG_ACTIVITY_NEW_TASK);
final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
//3 啓動Launcdr
mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
複製代碼
在註釋1處是對運行模式和Action的判斷,其中運行模式包括:非工廠模式、低級工廠模式和高級工廠模式。而Action的是是指啓動該Intent的Action,默認是Intent.ACTION_MAIN,表示是該應用的第一個啓動的Activity,通常在建立應用時,AndroidMainfest.xm中都會包含惟一個該標籤的Action。 而對於桌面應用,會增長Intent.HOME的標籤,若是咱們想自定義桌面應用,可在該應用的AndroidMainfest中的啓動Activity的Action添加android.Intent.action.HOME,以下所示:bash
<application
...
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.HOME"/>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
複製代碼
啓動Launer是在ActivityStarter的startHomeActivityLocked方法中完成,經過ActivityStackSupervisor將該Intent移動至HomeStack(用於存儲Launcher的變量)的頂部,最終調用startActivityLocked方法啓動該Intnet,實現對Launcer的啓動。app
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(reason);
...
}
複製代碼
完成Launcer的啓動後,做爲一個獨立的APP,Launcher開始執行應用的加載和桌面圖標的顯示。 ide
packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
protected void onCreate(Bundle savedInstanceState) {
...
//加載桌面顏色信息和監聽主題變化
WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
wallpaperColorInfo.setOnThemeChangeListener(this);
...
//加載桌面應用信息
LauncherAppState app = LauncherAppState.getInstance(this);
...
mModel = app.setLauncher(this);
...
//加載和設置桌面view
mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
setupViews();
...
if (!mModel.startLoader(currentScreen)) {
mDragLayer.setAlpha(0);
} else {
mWorkspace.setCurrentPage(currentScreen);
setWorkspaceLoading(true);
}
}
複製代碼
//設置launcher的監聽,初始化model
packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher); //傳入Launcher對象
return mModel;
}
複製代碼
在設置監聽時,傳入的Callbacks 對象時Launcher,是爲了在APP加載完成時,方便經過接口回調的形式返回值Launcher, 下面開始加載App。oop
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
Preconditions.assertUIThread();
mCallbacks = new WeakReference<>(callbacks);
}
}
//Callbacks 接口包含的內容以下,主要用到bindAllApplications
public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {
...
public void bindAllApplications(ArrayList<AppInfo> apps);
public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps);
public void bindAppsAdded(ArrayList<Long> newScreens,
ArrayList<ItemInfo> addNotAnimated,
ArrayList<ItemInfo> addAnimated);
public void bindPromiseAppProgressUpdated(PromiseAppInfo app);
public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user);
public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);
public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets);
...
}
複製代碼
加載的Task分析以下佈局
...
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
//開始加載
public boolean startLoader(int synchronousBindPage) {
...
synchronized (mLock) {
//清除以前的回調緩存
if (mCallbacks != null && mCallbacks.get() != null) {
final Callbacks oldCallbacks = mCallbacks.get();
// Clear any pending bind-runnables from the synchronized load process.
mUiExecutor.execute(new Runnable() {
public void run() {
oldCallbacks.clearPendingBinds();
}
});
// If there is already one running, tell it to stop.
stopLoader();
LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
mBgAllAppsList, synchronousBindPage, mCallbacks);//包含Callbacks對象
if (mModelLoaded && !mIsLoaderTaskRunning) { //已經加載完成且沒有正在加載
//加載完成後,開始將結果回調至Launcher
loaderResults.bindWorkspace();
loaderResults.bindAllApps(); //加載的回調
loaderResults.bindDeepShortcuts();
loaderResults.bindWidgets();
return true;
} else {
//開始不斷的加載 工做區間、全部的APP、快捷圖標和抽屜控件
startLoaderForResults(loaderResults);
}
}
}
return false;
}
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
public void startLoaderForResults(LoaderResults results) {
synchronized (mLock) {
//中止加載
stopLoader();
//建立新的加載task
mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
//在WorkerThread中執行該task
runOnWorkerThread(mLoaderTask);
}
}
//加載中涉及的線程初始化
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
static {
sWorkerThread.start();
}
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
複製代碼
經過LauncherModel的加載線程,獲取到了系統中全部的apps的信息,同時經過其Callbacks的接口,很方便的將結果傳遞出去,post
packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {
Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
public void run() {
bindAllApplications(apps);
}
};
...
//加載完成後AllAppsContainerView數據更新
mAppsView.setApps(apps);
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
}
複製代碼
數據回調值Launcher的bindAllApplications,開始對AllAppsContainerView界面進行數據設置,其設置的控制控件爲AlphabeticalAppsList,經過調用AlphabeticalAppsList實現對數據的設置處理,其實現流程和Recycleview的設置比較相似。
packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
public void setApps(List<AppInfo> apps) {
mApps.setApps(apps);
}
//數據傳遞控制控件中
packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
public void setApps(List<AppInfo> apps) {
mComponentToAppMap.clear();
addOrUpdateApps(apps);
}
packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
@Override
protected void onFinishInflate() {
...
mAppsRecyclerView = findViewById(R.id.apps_list_view); //能夠看到桌面應用部分的界面爲RecyclerView
mAppsRecyclerView.setApps(mApps);
mAppsRecyclerView.setLayoutManager(mLayoutManager);
mAppsRecyclerView.setAdapter(mAdapter);
mAppsRecyclerView.setHasFixedSize(true);
...
}
複製代碼
AllAppsContainerView會在XML佈局文件加載完成後,調用onFinishInflate方法,使加載的數據最終顯示在桌面上。造成咱們看到的桌面圖標。
在AllAppsContainerView設置adapter後,因爲RecyclerView不包含setOnItemClickListener方法,所以通常是在Adapter中自定義實現,可經過回調的形式將點擊事件傳遞出去,Launcher的執行流程以下:
//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
...
//建立新的Adapter
mAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);
mSpringAnimationHandler = mAdapter.getSpringAnimationHandler();
mApps.setAdapter(mAdapter);
...
}
複製代碼
設置點擊的監聽回調
//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsGridAdapter.java
public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
iconClickListener, View.OnLongClickListener iconLongClickListener) {
...
mIconClickListener = iconClickListener;
...
}
複製代碼
點擊事件的處理
packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
public void onClick(View v) {
...
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
onClickAppShortcut(v);
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if ((v instanceof PageIndicator) ||
(v == mAllAppsButton && mAllAppsButton != null)) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) {
startAppShortcutOrInfoActivity(v);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
}
}
}
//點擊桌面應用的快捷圖標的處理
protected void onClickAppShortcut(final View v) {
...
startAppShortcutOrInfoActivity(v);
...
}
private void startAppShortcutOrInfoActivity(View v) {
ItemInfo item = (ItemInfo) v.getTag();
Intent intent;
if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
intent = promiseAppInfo.getMarketIntent();
} else {
intent = item.getIntent();
}
...
//跳轉至相應的應用
boolean success = startActivitySafely(v, intent, item);
...
}
複製代碼
至此Launcher的啓動過程便分析完,總結以下: