概述
Activity启动的流程分为两部分:
-
一是在activity中通过startActivity(Intent intent)方法启动一个Activity;
-
二是我们在桌面通过点击应用图标启动一个App然后显示Activity;
第二种方式相较于第一种方式更加全面,所以本文会以第二种流程来分析。
简要
我们手机的桌面是一个叫做Launcher的Activity,它罗列了手机中的应用图标,图标中包含安装apk时解析的应用默认启动页等信息。在点击应用图标时,即将要启动的App和Launcher、AMS、Zygote所属进程不同所以涉及到Launcher与AMS,AMS与Zygote,AMS与新App这四者多次通信,才会启动一个App,然后再启动Activity,整体的时序图如下:
image
接下来根据源码来梳理一下流程。
1.Launcher向AMS发送启动Activity
Launcher本身是一个Activity,在用户点击应用图标时,调用startActivitySafely方法,最后调用到Activity.startActivity(),函数调用如下
Launcher.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
...
//标记在新的栈启动
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
startActivity(intent, optsBundle);
...
}
Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
...
if (options != null) {
//-1为requestCode表明不需要知道是否启动成功
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken,this,intent, requestCode, options);
...
}
每个Activity都持有Instrumentation对象,通过它的execStartActivity函数来继续完成启动Activity的流程,这个函数中传入了mMainThread.getApplicationThread(),它获取到的是ActivityThread的内部类ApplicationThread,这是一个Binder对象,之后AMS通过此对象与App的通信。
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(),
who.getAttributionTag(),intent,intent.resolveTypeIfNeeded(who.getContentResolver()),
token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
...
}
ActivityTaskManager.java
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
}
};
这一步Launcher开始向AMS通信,由于在不同的进程所以需要通过Binder来通信,IActivityTaskManager是一个代理AMS端Binder的对象,之后AMS开始startActivity。 到这里Launcher向AMS请求启动一个Activity的流程就结束了。
2.AMS启动Activity并通知Launcher进入Paused
现在的流程是在AMS中,也就是另一个进程中,上一步通过代理调用到AMS的startActivity方法,接下来的调用如下:
ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
...
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
上面几步主要是做权限检查
ActivityStarter.java
int execute() {
...
res = executeRequest(mRequest);
...
}
//层层调用会到下面这个方法
ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
if (mResumedActivity != null) {
pausing |= startPausingLocked(userLeaving, false , next);
}
...
mStackSupervisor.startSpecificActivity(next, true, false);
...
}
startPausingLocked方法主要是通知Launcher进入Paused状态,在它进入这个状态后,在ActivityStackSupervisor.startSpecificActivity方法判断新的App进程状态做出不同响应,如下:
ActivityStackSupervisor.java
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// 获取要启动的Activity进程信息
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
//如果进程存在且有进程中有线程存在 就是启动一个同应用的Activity(普通Activity就在此执行)
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
//否则通过AMS向Zygote进程请求创建新的进程
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
截止到这里完成了Launcher和AMS的通信,以及AMS和Zygote进程的通信,接下来我们要创建要启动的App的线程,即ActivityThread。
3.新的进程启动,ActivityThread的main函数
上一部分Zygote启动新的进程时标记ActivityThread.main函数,在Zygote创建好新进程后通过反射调用此方法,现在处于新App的进程中。
ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
Looper.loop();
...
}
private void attach(boolean system, long startSeq) {
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.mDisabledCompatChanges);
...
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
...
}
这里主要是创建了Looper和ActivityThread对象,然后将当前应用ApplicationThread注册到AMS中,ApplicationThread是ActivityThread的内部类实现了IApplicationThread.Stub用此对象可跨进程通信。
最后
以上就是缓慢酒窝为你收集整理的关于 Activity 启动流程的知识点汇总的全部内容,希望文章能够帮你解决关于 Activity 启动流程的知识点汇总所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复