相關文章鏈接:
1. Android Framework - 學習啓動篇
2. Android 系統服務 - AMS 的啓動過程
3. Android 系統服務 - PMS 的啓動過程
4. Android Framework - 開機啓動 Init 進程
相關源碼文件:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/apps/Launcher3/src/com/android/launcher3/launcher3.java
/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
/apps/Launcher3/src/com/android/launcher3/LauncherAppsCompatV16.java
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
/frameworks/base/cmds/bootanimation/bootanimation_main.cpp
1. 啓動入口分析
public void systemReady(final Runnable goingCallback) {
synchronized (this) {
// 啓動 Launcher
startHomeActivityLocked(mCurrentUserId, "systemReady");
}
}
boolean startHomeActivityLocked(int userId, String reason) {
// 獲取 Launcher 的啓動意圖
Intent intent = getHomeIntent();
// 通過意圖解析到 ActivityInfo
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);
// 通過進程名和uid 查詢進程信息
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
// 這裏進程還沒啓動 app 爲 null
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo, reason);
}
}
return true;
}
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// 用 CATEGORY_HOME 去查詢
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
Launcher 啓動的入口方法在 AMS 的 systemReady 方法中,首先會通過意圖向 PMS 發起解析請求,PMS 查詢返回 ActivityInfo 對象,注意這裏的 category 是 CATEGORY_HOME ;然後通過進程的名字和 uid 去查詢是否啓動了進程,目前 Launcher 進程的 ProcessRecord 肯定是空;最後調用 startHomeActivity 方法去啓動和創建 Launcher 。關於 Launcher 進程的創建和 Launcher Activity 的啓動流程這裏先不講,在後面分析四大組件的啓動過程時會詳細講到。
2. 查詢解析填充所有 App 信息
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化 Model
LauncherAppState app = LauncherAppState.getInstance();
mModel = app.setLauncher(this);
setContentView(R.layout.launcher);
if (!mRestoring) {
if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
// If the user leaves launcher, then we should just load items asynchronously when
// they return.
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());
}
}
}
public void startLoader(int synchronousBindPage, int loadFlags) {
synchronized (mLock) {
if (mCallbacks != null && mCallbacks.get() != null) {
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);
}
}
}
}
public void run() {
loadAndBindAllApps();
}
private void loadAllApps() {
final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfoCompat app = apps.get(i);
mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));
}
mHandler.post(new Runnable() {
public void run() {
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(added);
} else {
...
}
}});
}
public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user) {
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(packageName);
// 像 PMS 發起查詢所有 ResolveInfo 信息
List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
List<LauncherActivityInfoCompat> list = new ArrayList<LauncherActivityInfoCompat>(infos.size());
for (ResolveInfo info : infos) {
list.add(new LauncherActivityInfoCompatV16(mContext, info));
}
return list;
}
Launcher 應用的 onCreate 方法中會調用 mModel 的 startLoader 方法去查詢所有的 App 應用信息,該方法的內部實際調用的是 PKMS 的 queryIntentActivities 方法。並且會將所有查詢到的 Apk 信息,通過回調的方式通知 Launcher 去填充我們桌面的 RecyclerView 界面。注意這裏查詢的 Action 和 Category 分別是 ACTION_MAIN 和 CATEGORY_LAUNCHER ,因爲我們在 AndroidMnifest.xml 中一般都會有如下配置。
<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3. 啓動和關閉開機畫面
啓動完 Launcher 後系統會幫我們關閉開機啓動的畫面,所以這裏我們順便講一下開機畫面的啓動和關閉。我們首先來分析一下開機動畫的啓動,開機動畫其實是 init 進程中解析到的一個服務,只不過 init.rc 腳本中的配置是 disable 。也就是說 init 進程啓動的時候只會解析到,而不會啓動開機動畫的進程,因爲開機動畫進程需要處理渲染,因此必須要依賴 SurfaceFlinger 進程初始化完畢。
service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled
oneshot
void SurfaceFlinger::init() {
// start boot animation
startBootAnim();
}
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}
SurfaceFlinger 初始化完畢後會通過 property_set 這種方式去通知 init 進程啓動 bootanim 進程,因此我們只需要找到 bootanim 進程的啓動源碼即可。
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
// 打開 binder 驅動
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
// 獲取初始化 layer
...
// 初始化 opengl and egl
...
// 初始化打開開機啓動 zip 包
...
return NO_ERROR;
}
bool BootAnimation::threadLoop()
{
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZip == NULL) {
...
} else {
r = movie();
}
// 銷燬 opengl 和 egl
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
}
bool BootAnimation::movie()
{
String8 desString;
// 讀取 desc.txt 配置文件
if (!readFile("desc.txt", desString)) {
return false;
}
char const* s = desString.string();
// 解析描述文件
for (;;) {
...
}
for (size_t i=0 ; i<pcount ; i++) {
for (int r=0 ; !part.count || r<part.count ; r++) {
// opengl 繪製操作
glClearColor(
part.backgroundColor[0],
part.backgroundColor[1],
part.backgroundColor[2],
1.0f);
for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
...
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
...
initTexture(frame);
}
// specify the y center as ceiling((mHeight - animation.height) / 2)
// which is equivalent to mHeight - (yc + animation.height)
glDrawTexiOES(xc, mHeight - (yc + animation.height),
0, animation.width, animation.height);
eglSwapBuffers(mDisplay, mSurface);
// 不斷繪製時檢測是否需要退出
checkExit();
}
// 如果退出了就跳出結束繪製
if(exitPending() && !part.count)
break;
}
// free the textures for this part
if (part.count != 1) {
for (size_t j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
}
}
return false;
}
// 讀取 service.bootanim.exit 值是否是 1
#define EXIT_PROP_NAME "service.bootanim.exit"
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
if (exitnow) {
requestExit();
if (mAudioPlayer != NULL) {
mAudioPlayer->requestExit();
}
}
}
啓動動畫底層採用的是 opengles 的方式來渲染繪製的,繪製的內容是本地的一個啓動動畫資源包,在繪製的過程中會不斷的判斷是否需要退出,讀取的字段是 service.bootanim.exit ,爲 1 代表需要 break 退出循環繪製。因此我們只需要找到 service.bootanim.exit 在哪裏設置爲 1 的,便可找到退出啓動動畫的入口。關閉動畫的入口還是在 SurfaceFlinger 中只是這個調用流程比較複雜而已:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
// 添加了一個 IdleHandler 消息
Looper.myQueue().addIdleHandler(new Idler());
}
} else {
...
}
}
private class Idler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
if (a != null) {
mNewActivities = null;
IActivityManager am = ActivityManagerNative.getDefault();
ActivityClientRecord prev;
do {
if (a.activity != null && !a.activity.mFinished) {
try {
// 調用 AMS 的 activityIdle
am.activityIdle(a.token, a.createdConfig, stopProfiling);
} catch (RemoteException ex) {
// Ignore
}
}
} while (a != null);
}
return false;
}
}
@Override
public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
synchronized (this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config);
}
}
Binder.restoreCallingIdentity(origId);
}
// Checked.
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
Configuration config) {
ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
...
if (isFrontStack(r.task.stack) || fromTimeout) {
booting = checkFinishBootingLocked();
}
}
...
return r;
}
private boolean checkFinishBootingLocked() {
final boolean booting = mService.mBooting;
boolean enableScreen = false;
mService.mBooting = false;
if (!mService.mBooted) {
mService.mBooted = true;
enableScreen = true;
}
if (booting || enableScreen) {
mService.postFinishBooting(booting, enableScreen);
}
return booting;
}
void enableScreenAfterBoot() {
mWindowManager.enableScreenAfterBoot();
synchronized (this) {
updateEventDispatchingLocked();
}
}
public void performEnableScreen() {
synchronized(mWindowMap) {
if (!mBootAnimationStopped) {
// 像 SurfaceFlinger 進程發起關閉開機界面的消息
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
...
}
mBootAnimationStopped = true;
}
...
}
}
}
void SurfaceFlinger::bootFinished() {
...
// 把 service.bootanim.exit 屬性設置爲 1 ,bootanim 進程讀到 1 時就會退出開機啓動動畫
property_set("service.bootanim.exit", "1");
}
關閉開機啓動動畫的流程還是比較複雜的,我們來縷一縷整個邏輯,我們的 Launcher 進程啓動後會啓動我們 Launcher Activity 界面,而 Activity 的生命週期調用都是由 ActivityThread 來執行的,其中就會執行到 handleResumeActivity 方法,在該方法中會添加一個 IdleHandler 消息,會調用到 AMS 的 activityIdle 方法,AMS 會調用 WMS 的 enableScreenAfterBoot 方法,WMS 會跨進程通知 SurfaceFlinger 去關閉我們的開機啓動動畫。
視頻地址:https://pan.baidu.com/s/1LZ-kHXQyxa9995I_P1ajfg
視頻密碼:o71f