我们都知道android手机开机后会首先看到"ANDROID"启动页面,然后看到手机桌面,而手机桌面就是android机子启动的第一个Activity。那么android系统是如何启动这个HOME Activity的呢?
借助前面博文《android zygote进程启动到SystemServer进程启动过程》我们知道,通电开机后会走到SystemServer.java的 run( ) 方法。
run方法大概可以分为下面几步:
在初始化上下文对象之后会启动各种系统服务:
startBootstrapServices(); //启动引导服务
startCoreServices(); //启动核心服务
startOtherServices(); //启动其他服务
private void startOtherServices() {
//.......
mActivityManagerService.systemReady(() -> {
//.......
}, BOOT_TIMINGS_TRACE_LOG);
}
上面启动一堆堆的服务后会调用ActivityManagerService的systemReady( )方法:
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
//.......
synchronized (this) {
//.......
startHomeActivityLocked(currentUserId, "systemReady");
//.......
}
}
boolean startHomeActivityLocked(int userId, String reason) {
//......
Intent intent = getHomeIntent(); //注释1
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); //注释2
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); //注释3
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
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:
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
try {
if (comp != null) { //comp默认为null
// Factory test.
ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
//会走到这里
ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags, userId);
if (info != null) {
ai = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
return ai;
}
AppGlobals.getPackageManager()返回IPackageManager对象,但IPackageManager是一个借口,经过查找,可以知道返回的是PackageManagerService对象,接着调用其resolveIntent()方法:
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {
return resolveIntentInternal(intent, resolvedType, flags, userId, false, Binder.getCallingUid());
}
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
int flags, int userId, boolean resolveForStart, int filterCallingUid) {
try {
//日志跟踪
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
//启动后userId都会有一个id,故此不为null
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
//检查权限
mPermissionManager.enforceCrossUserPermission(callingUid, userId, false , false, "resolve intent");
//日志跟踪
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
//重头戏:查找出Intent.CATEGORY_HOME的Activity
final List query = queryIntentActivitiesInternal(intent, resolvedType,
flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
//日志跟踪
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
//帅选出d对应的HomeActivity,然后返回该Activity的相关信息
final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId);
return bestChoice;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
注释3:调用ActivityStartController的startHomeActivity( )方法启动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();
}
}
至于怎么去查找和帅选出对应的Home Activity,后续我们再去探讨。以上就是开启桌面Activity的部分过程。