赞
踩
前面我们分析了init进程,zygote进程,SystemServer进程,本篇的Launcher是系统启动流程的最后一个进程。
Launcher进程是一个系统的应用程序,位于packages/apps/Launcher3中,它用于显示已经安装的应用程序,它通过访问PackageManagerService获取安装的应用程序,然后将他们封装成一个个的快捷图标显示到屏幕上,每一个图标包含了被启动应用程序的Intent信息,点击之后就可以启动对应应用程序。
private void startOtherServices() {
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
...
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
}
}
}
Launcher的入口函数在System.startOtherServices方法中,我们进入systemReady方法中:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback) {
...
mStackSupervisor.resumeFocusedStackTopActivityLocked();
...
}
进入到了ActivityStackSupervisor.resumeFocusedStackTopActivityLocked中
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked() { return resumeFocusedStackTopActivityLocked(null, null, null); } boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (targetStack != null && isFocusedStack(targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } final ActivityRecord r = mFocusedStack.topRunningActivityLocked(); if (r == null || r.state != RESUMED) { mFocusedStack.resumeTopActivityUncheckedLocked(null, null); } return false; }
在上面最后调用到了mFocusedStack.resumeTopActivityUncheckedLocked
,mFocusedStack是ActivityStack类型的,我们进入查看源码:
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { if (mStackSupervisor.inResumeTopActivity) { // Don't even start recursing. return false; } boolean result = false; try { // Protect against recursion. mStackSupervisor.inResumeTopActivity = true; if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) { mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN; mService.updateSleepIfNeededLocked(); } result = resumeTopActivityInnerLocked(prev, options); } finally { mStackSupervisor.inResumeTopActivity = false; } return result; } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ... final TaskRecord prevTask = prev != null ? prev.task : null; if (next == null) { /*** * 这里启动了Launcher */ return isOnHomeDisplay() && mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason); } }
上面从resumeTopActivityUncheckedLocked调用到了resumeTopActivityInnerLocked中,最后调用到了ActivityStackSupervisor.resumeHomeStackTask函数。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
...
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
mService.setFocusedActivityLocked(r, myReason);
return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
接着进入到了ActivityManagerService.startHomeActivityLocked
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
boolean startHomeActivityLocked(int userId, String reason) { if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopAction == null) { // We are running in factory test mode, but unable to find // the factory test app, so just sit around displaying the // error message and don't try to start anything. return false; } // 1 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.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); mActivityStarter.startHomeActivityLocked(intent, aInfo, reason); } } else { Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); } return true; }
在注释1处的getHomeIntent方法代码如下:
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);//1
}
return intent;
}
在注释1处添加了一个CATEGORY_HOME
,CATEGORY_HOME = "android.intent.category.HOME"
,这里我们锁定就是启动了Launcher页面,因为我们查看系统应用Launcher的清单文件中匹配了它,Launcher的清单文件如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher3"> <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="16"/> <uses-permission android:name="android.permission.CALL_PHONE" /> ... <application android:allowBackup="@bool/enable_backup" android:backupAgent="com.android.launcher3.LauncherBackupAgentHelper" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher_home" android:label="@string/app_name" android:largeHeap="@bool/config_largeHeap" android:restoreAnyVersion="true" android:supportsRtl="true" > <activity android:name="com.android.launcher3.Launcher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:theme="@style/Theme" android:windowSoftInputMode="adjustPan" android:screenOrientation="nosensor" android:configChanges="keyboard|keyboardHidden|navigation" android:resumeWhilePausing="true" android:taskAffinity="" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.MONKEY"/> </intent-filter> </activity> </application> </manifest>
从上面可以看出Launcher的intent-filter匹配了上面的Intent,所以Launcher就被启动起来了。就会执行onCreate方法。
Launcher.onCreate函数如下:
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //1 LauncherAppState app = LauncherAppState.getInstance(); //2 mModel = app.setLauncher(this); setContentView(R.layout.launcher); if (!mRestoring) { //3 mModel.startLoader(PagedView.INVALID_RESTORE_PAGE); } else { // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground mModel.startLoader(mWorkspace.getRestorePage()); } } }
注释1处单例获取LauncherAppState的实例,在注释2处调用它的setLauncher函数并将Launcher对象传入,setLauncher函数如下所示:
packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java
LauncherModel setLauncher(Launcher launcher) {
getLauncherProvider().setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
mAccessibilityDelegate = ((launcher != null) && Utilities.ATLEAST_LOLLIPOP) ?
new LauncherAccessibilityDelegate(launcher) : null;
return mModel;
}
接着调用到了LauncherModel的initialize函数:
packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
/**
* Set this as the current Launcher activity object for the loader.
*/
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
// Disconnect any of the callbacks and drawables associated with ItemInfos on the
// workspace to prevent leaking Launcher activities on orientation change.
unbindItemInfosAndClearQueuedBindRunnables();
mCallbacks = new WeakReference<Callbacks>(callbacks);
}
}
我们看到上面其实就是设置了一个回调函数,回调函数就是Launcher自身,不过是以一个弱引用的方式,这个回调后面会用到。
接着分析onCreate中的注释3的部分,launcherModel.startLoader方法:
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); static { sWorkerThread.start(); } @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper()); public void startLoader(int synchronousBindPage, int loadFlags) { // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems InstallShortcutReceiver.enableInstallQueue(); synchronized (mLock) { // Clear any deferred bind-runnables from the synchronized load process // We must do this before any loading/binding is scheduled below. synchronized (mDeferredBindRunnables) { mDeferredBindRunnables.clear(); } // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { // If there is already one running, tell it to stop. stopLoaderLocked(); mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags); if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) { mLoaderTask.runBindSynchronousPage(synchronousBindPage); } else { sWorkerThread.setPriority(Thread.NORM_PRIORITY); sWorker.post(mLoaderTask); } } } }
上面创建了一个HandlerThread的子线程的Handler,用来处理耗时任务,在上面的最后post了一个任务,这个任务的类是LoaderTask.java,实现了Runnable接口,run方法如下:
public void run() { synchronized (mLock) { if (mStopped) { return; } mIsLoaderTaskRunning = true; } // Optimize for end-user experience: if the Launcher is up and // running with the // All Apps interface in the foreground, load All Apps first. Otherwise, load the // workspace first (default). keep_running: { if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); //1 loadAndBindWorkspace(); if (mStopped) { break keep_running; } waitForIdle(); // second step if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps"); // 2 loadAndBindAllApps(); } // Clear out this reference, otherwise we end up holding it until all of the // callback runnables are done. mContext = null; synchronized (mLock) { // If we are still the last one to be scheduled, remove ourselves. if (mLoaderTask == this) { mLoaderTask = null; } mIsLoaderTaskRunning = false; mHasLoaderCompletedOnce = true; } }
上面的两个注释写的很清楚,在注释1处loadAndBindWorkspace是加载工作空间,在注释2处loadAndBindAllApps用来加载所有的app。
loadAndBindAllApps源码如下:
private void loadAndBindAllApps() { if (DEBUG_LOADERS) { Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded); } if (!mAllAppsLoaded) { // 1 loadAllApps(); synchronized (LoaderTask.this) { if (mStopped) { return; } } updateIconCache(); synchronized (LoaderTask.this) { if (mStopped) { return; } mAllAppsLoaded = true; } } else { onlyBindAllApps(); } }
注释1处调用了loadAllApps(),源码如下:
private void loadAllApps() {
...
mHandler.post(new Runnable() {
public void run() {
final long bindTime = SystemClock.uptimeMillis();
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(added);//1
...
}
}
});
...
}
这里的callbacks就是上面弱引用存储的Launcher,所以我们直接查看Launcher中的bindAllApplications,代码如下:
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {
if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
mTmpAppsList = apps;
return;
}
if (mAppsView != null) {
//1
mAppsView.setApps(apps);
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
}
在注释1处调用了 mAppsView的setApps,mAppsView是一个AllAppsContainerView类型的,我们查看它的setApps方法:
packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java
private final AlphabeticalAppsList mApps;
public void setApps(List<AppInfo> apps) {
mApps.setApps(apps);
}
这里我们查看onFinishInflate函数
private AllAppsRecyclerView mAppsRecyclerView; @Override protected void onFinishInflate() { super.onFinishInflate(); //1 初始化控件 mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view); //2 传递应用 mAppsRecyclerView.setApps(mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); //3 设置adapter mAppsRecyclerView.setAdapter(mAdapter); mAppsRecyclerView.setHasFixedSize(true); mAppsRecyclerView.addOnScrollListener(mElevationController); mAppsRecyclerView.setElevationController(mElevationController); }
onFinishInflate在xml加载完成之后就会调用,这里launcher中app的显示逻辑和我们平时将数据显示到一个RecyclerView上基本一致,所以这里也比较好理解。
在此对整个Android系统启动流程做一个全面的总结:
1 按Power键启动电源及系统启动
当按下电源键,引导芯片代码开始从固化在ROM中预定义的地方开始执行,加载引导程序Bootloader到RAM,然后执行引导程序。
2 引导程序Bootloader
引导程序是Android操作系统被拉起来之前的一个程序,类似于window一样,它的作用就是把系统拉起运行起来。它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qibootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。
3 linux内核启动
Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
4 init进程启动
创建和挂载启动所需要的文件目录,初始化和启动属性服务,解析init.rc配置并且启动Zygote进程。
5 Zygote进程启动
创建JavaVM并为JavaVM注册JNI,创建服务端Socket,启动SystemServer进程。
6 SystemServer进程启动
启动Binder线程池和SystemServiceManager,并且启动各种系统服务。
7 Launcher启动
被SystemServer进程启动的ActivityManagerService会启动Launcher,Launcher启动后会将已安装应用的快捷图标显示到界面上。
1 Android系统启动流程? 答案如上所述
2 什么是写时拷贝(copy- on-write)?
写时拷贝copy_on_write技术: fork的实现是使用copy_on_write技术实现的,它是一种可以推迟甚至避免拷贝的技术,内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间,只有在子进程真正需要写入数据的时候才会赋值地址空间,从而使得每个进程拥有自己的进程空间,也就是说资源的复制是在需要写入数据的时候才会进行,在此之前只会以只读的形式共享。
3 孤儿进程和僵尸进程是什么?
fork系统调用之后,父子进程将交替执行,执行顺序不定。如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程(僵尸进程:只保留一些退出信息供父进程查询).
4 system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?
Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork() 时基于 Copy-On-Write 机制创建的其他进程就能直接使用这些资源,而不用重新加载。比如 system_server 就可以直接使用 Zygote 中的 JNI函数、共享库、常用的类、以及主题资源。
5 为什么要专门使用 Zygote 进程去孵化应用进程,而不是让 system_server 去孵化呢?
system_server 相比 Zygote 多运行了 AMS、WMS 等服务,这些对一个应用程序来说是不需要的。另外进程的 fork() 对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而system_server 中肯定是有很多线程的。
6 多线程的进程fork调用为什么会导致死锁?
多线程的进程的fork调用:复制整个用户空间的数据(通常使用 copy-on-write 的策略,
所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。当子进程想 lock 这个锁时,不再有任何手段可以解开了。程序发生死锁
7 Zygote 为什么不采用 Binder 机制进行 IPC 通信?
Binder 机制中存在 Binder 线程池,是多线程的,如果 Zygote 采用 Binder 的话就存在上面说的fork() 与 多线程的问题了。其实严格来说,Binder 机制不一定要多线程,所谓的 Binder 线程只不过是在循环读取 Binder 驱动的消息而已,只注册一个 Binder 线程也是可以工作的,比如 service manager就是这样的。实际上 Zygote 尽管没有采取 Binder 机制,它也不是单线程的,但它在 fork() 前主动停止了其他线程,fork() 后重新启动了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。