Android的Launcher啟動過程分析(1)
通過上篇文章我們了解了AndroidLauncher的啟動過程阶牍,下面我們繼續(xù)探究點擊Launcher中圖片啟動應用的過程腿倚。
通過上篇文章我們知道卵贱,最終ActivityStartController的startHomeActivity(Intent intent, ActivityInfo aInfo, String reason)函數(shù)啟動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();
}
}
最終會調用ActivityStarter.startActivity函數(shù)將各種啟動參數(shù)輸入。
下面我們來看Launcher的onCreat方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
LauncherAppState app = LauncherAppState.getInstance();//tag1
mDeviceProfile = getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE ?
app.getInvariantDeviceProfile().landscapeProfile
: app.getInvariantDeviceProfile().portraitProfile;
mSharedPrefs = Utilities.getPrefs(this);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
mModel = app.setLauncher(this);//tag2
....
if (!mRestoring) {
if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);//2
} else {
mModel.startLoader(mWorkspace.getRestorePage());
}
}
...
}
tag1處獲取LauncherAppState的實例并在注釋tag2處調用它的setLauncher函數(shù)并將Launcher對象傳入诫欠,LauncherAppState的setLauncher函數(shù)如下所示:
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
return mModel;
}
我們看到mModel.initialize(launcher)函數(shù)涵卵,代碼如下:
/**
* Set this as the current Launcher activity object for the loader.
*/
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
Preconditions.assertUIThread();
mCallbacks = new WeakReference<>(callbacks);
}
}
在initialize函數(shù)中會將Callbacks浴栽,也就是傳入的Launcher 封裝成一個弱引用對象荒叼。因此我們得知mCallbacks變量指的就是封裝成弱引用對象的Launcher,這個mCallbacks后文會用到它典鸡。
再回到Launcher的onCreate函數(shù)被廓,在tag2處調用了LauncherModel的startLoader函數(shù):
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");//tag1
static {
sWorkerThread.start();
}
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());//tag2
...
public boolean startLoader(int synchronousBindPage) {
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
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) {
final Callbacks oldCallbacks = mCallbacks.get();
// Clear any pending bind-runnables from the synchronized load process.
mUiExecutor.execute(oldCallbacks::clearPendingBinds);
// If there is already one running, tell it to stop.
stopLoader();
LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
mBgAllAppsList, synchronousBindPage, mCallbacks);//tag3
if (mModelLoaded && !mIsLoaderTaskRunning) {
// Divide the set of loaded items into those that we are binding synchronously,
// and everything else that is to be bound normally (asynchronously).
loaderResults.bindWorkspace();
// For now, continue posting the binding of AllApps as there are other
// issues that arise from that.
loaderResults.bindAllApps();
loaderResults.bindDeepShortcuts();
loaderResults.bindWidgets();
return true;
} else {
startLoaderForResults(loaderResults);
}
}
}
return false;
}
tag1處創(chuàng)建了具有消息循環(huán)的線程HandlerThread對象。tag2處創(chuàng)建了Handler萝玷,并且傳入HandlerThread的Looper嫁乘。Hander的作用就是向HandlerThread發(fā)送消息的,如果已經(jīng)load或者正在load就直接綁定數(shù)據(jù)球碉,否者接著看startLoaderForResults函數(shù)如下:
public void startLoaderForResults(LoaderResults results) {
synchronized (mLock) {
stopLoader();
mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
runOnWorkerThread(mLoaderTask);
}
}
我們看到先將load任務停止蜓斧,然后創(chuàng)建一個LoaderTask(Runnable)對像,同時調用 runOnWorkerThread(mLoaderTask);函數(shù)如下:
/** Runs the specified runnable immediately if called from the worker thread, otherwise it is
* posted on the worker thread handler. */
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);
}
}
如果沒有工作在worker thread線程的話直接調用handler通訊將Runnable發(fā)送給HandlerThread睁冬,否者直接調用Runnable的run函數(shù)挎春,LoaderTask的run方法如下:
public void run() {
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
loadWorkspace();
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
mResults.bindWorkspace();
// Notify the installer packages of packages with active installs on the first screen.
TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast");
sendFirstScreenActiveInstallsBroadcast();
// Take a break
TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
waitForIdle();
verifyNotStopped();
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
loadAllApps();
TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
verifyNotStopped();
mResults.bindAllApps();
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
updateIconCache();
// Take a break
TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
waitForIdle();
verifyNotStopped();
// third step
TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts");
loadDeepShortcuts();
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts");
mResults.bindDeepShortcuts();
// Take a break
TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle");
waitForIdle();
verifyNotStopped();
// fourth step
TraceHelper.partitionSection(TAG, "step 4.1: loading widgets");
mBgDataModel.widgetsModel.update(mApp, null);
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets");
mResults.bindWidgets();
transaction.commit();
} catch (CancellationException e) {
// Loader stopped, ignore
TraceHelper.partitionSection(TAG, "Cancelled");
}
TraceHelper.endSection(TAG);
}
auncher是用工作區(qū)的形式來顯示系統(tǒng)安裝的應用程序的快捷圖標,每一個工作區(qū)都是來描述一個抽象桌面的豆拨,它由n個屏幕組成直奋,每個屏幕又分n個單元格,每個單元格用來顯示一個應用程序的快捷圖標施禾。step 1.1處調用loadWorkspace()函數(shù)用來加載工作區(qū)信息脚线,step 1.2調用 mResults.bindWorkspace()來綁定工作區(qū)信息;step2.1處的loadAllApps()函數(shù)是用來加載系統(tǒng)已經(jīng)安裝的應用程序信息弥搞,step2.2處調用mResults.bindAllApps()綁定已安裝應用程序信息邮绿,這里我們來看下loadAllApps函數(shù)代碼如下所示:
private void loadAllApps() {
final List<UserHandle> profiles = mUserManager.getUserProfiles();
// Clear the list of apps
mBgAllAppsList.clear();
for (UserHandle user : profiles) {
// Query for the set of apps
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
// Fail if we don't have any apps
// TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
return;
}
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
}
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
// get all active sessions and add them to the all apps list
for (PackageInstaller.SessionInfo info :
mPackageInstaller.getAllVerifiedSessions()) {
mBgAllAppsList.addPromiseApp(mApp.getContext(),
PackageInstallerCompat.PackageInstallInfo.fromInstallingState(info));
}
}
mBgAllAppsList.added = new ArrayList<>();
通過LauncherAppsCompat.getActivityList(null, user)函數(shù)獲取app渠旁,并且封裝成AppInfo存儲在mBgAllAppsList中,這里的getActivityList函數(shù)是調用的LauncherAppsCompatVL中的船逮,代碼如下:
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
ParceledListSlice<ResolveInfo> activities = null;
try {
activities = mService.getLauncherActivities(packageName, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
if (activities == null) {
return Collections.EMPTY_LIST;
}
ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
for (ResolveInfo ri : activities.getList()) {
LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
if (DEBUG) {
Log.v(TAG, "Returning activity for profile " + user + " : "
+ lai.getComponentName());
}
lais.add(lai);
}
return lais;
}
我們看到mService.getLauncherActivities(packageName, user)一死,這里的mService是 ILauncherApps.aidl,通過IPC獲取ILauncherApps的∩低伲回到LoaderTask的run方法中投慈,我們看到繼續(xù)執(zhí)行step2.2 mResults.bindAllApps(),代碼如下:
public void bindAllApps() {
// shallow copy
@SuppressWarnings("unchecked")
final ArrayList<AppInfo> list = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();
Runnable r = new Runnable() {
public void run() {
Callbacks callbacks = mCallbacks.get();
if (callbacks != null) {
callbacks.bindAllApplications(list);
}
}
};
mUiExecutor.execute(r);
}
這里的callBacks就是Launcher實例冠骄,所以我們直接去看Launcher的bindAllApplications方法代碼如下:
public void bindAllApplications(ArrayList<AppInfo> apps) {
mAppsView.getAppsStore().setApps(apps);//tag1
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
}
在tag1處會調用AllAppsContainerView的setApps函數(shù)伪煤,并將包含應用信息的列表apps傳進去,AllAppsContainerView的setApps函數(shù)如下所示:
包含應用信息的列表apps已經(jīng)傳給了AllAppsContainerView凛辣,查看AllAppsContainerView的setApps函數(shù):
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
recyclerView.setApps(appsList, mUsingTabs);//tag1
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);//tag2
recyclerView.setHasFixedSize(true);
// No animations will occur when changes occur to the items in this RecyclerView.
recyclerView.setItemAnimator(null);
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
recyclerView.addItemDecoration(focusedItemDecorator);
adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
applyVerticalFadingEdgeEnabled(verticalFadingEdge);
applyPadding();
}
tag1處得到AllAppsRecyclerView用來顯示App列表抱既,并將apps的信息列表傳進去,并在tag2處為AllAppsRecyclerView設置Adapter扁誓。這樣應用程序快捷圖標的列表就會顯示在屏幕上防泵。
Launcher啟動流程就講到這里,不足之處還請指正蝗敢。
總結一下Android系統(tǒng)的啟動流程大體如下:
1.啟動電源以及系統(tǒng)啟動
當電源按下時引導芯片代碼開始從預定義的地方(固化在ROM)開始執(zhí)行捷泞。加載引導程序Bootloader到RAM,然后執(zhí)行寿谴。
2.引導程序BootLoader
引導程序BootLoader是在Android操作系統(tǒng)開始運行前的一個小程序锁右,它的主要作用是把系統(tǒng)OS拉起來并運行。
3.Linux內核啟動
內核啟動時讶泰,設置緩存咏瑟、被保護存儲器、計劃列表痪署、加載驅動码泞。當內核完成系統(tǒng)設置,它首先在系統(tǒng)文件中尋找init.rc文件狼犯,并啟動init進程余寥。
4.init進程啟動
初始化和啟動屬性服務,并且啟動Zygote進程辜王。
5.Zygote進程啟動
創(chuàng)建JavaVM并為JavaVM注冊JNI劈狐,創(chuàng)建服務端Socket,啟動SystemServer進程呐馆。
6.SystemServer進程啟動
啟動Binder線程池和SystemServiceManager肥缔,并且啟動各種系統(tǒng)服務。
7.Launcher啟動
被SystemServer進程啟動的ActivityManagerService會啟動Launcher汹来,Launcher啟動后會將已安裝應用的快捷圖標顯示到界面上续膳。