一个电话面中提及到的问题,忘了是App启动还是Activity启动(那就顺便都分析一遍)。这里进行一下源码的分析,给自己加深下印象。
源码准备
由于Android的源码部分有的是@hide标注的,所以呢在用AS找类的时候会比较的麻烦,一对报红的情况,所以呢在分析之前需要先解决一下这个问题。
解决办法有两个
方法一.
将SDK源码全部导入AS或Eclipse,依然麻烦,为了查看一两个API而导入上百M的代码很不划算!
方法二.
在GitHub已有人去除Android.jar中@hide注解 地址: github.com/anggrayudi/…
1.下载对应API版本Android.jar 2.替换路径SDK/platforms/android-版本/Android.jar 3.重新打开IDE就可以查看
方法二还有额外便利,就是可以直接使用隐藏API,不需要反射(浪费性能又麻烦又易写错) Android.jar并不会打包到APK,所以去除@hide的Android.jar,只是欺骗IDE/编译器,方便程序员查看使用!
我这里是用的方法二,替换了api28的包,准备好这些我们就可以开始了
源码分析
1.Launcher
1.1 Launcher的主Activity——Launcher.java中,点击app图标之后会回调其中的onclick方法。
Launcher代码地址
public void onClick(View v) {
...
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
// 从快捷方式图标启动
onClickAppShortcut(v);
} else if (tag instanceof FolderInfo) {
// 文件夹
if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if (v == mAllAppsButton) {
// “所有应用”按钮
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) {
// 从“所有应用”中启动的应用
startAppShortcutOrInfoActivity(v);
} else if (tag instanceof LauncherAppWidgetInfo) {
// 组件
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
}
}
}
1.2 Launcher.onClickAppShortcut会调用startAppShortcutOrInfoActivity 方法:
@Thunk void startAppShortcutOrInfoActivity(View v) {
Object tag = v.getTag();
final ShortcutInfo shortcut;
final Intent intent;
if (tag instanceof ShortcutInfo) {
shortcut = (ShortcutInfo) tag;
// 取出对应的 Intent 对象
intent = shortcut.intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
} else if (tag instanceof AppInfo) {
shortcut = null;
intent = ((AppInfo) tag).intent;
} else {
throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
}
// 调用 startActivitySafely 方法
boolean success = startActivitySafely(v, intent, tag);
mStats.recordLaunch(v, intent, shortcut);
if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
}
1.3 用取出来的Intent调用startActivity
private boolean startActivity(View v, Intent intent, Object tag) {
// 启动新的任务栈
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
...
if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
try {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().build());
// 调用 Activity 的 startActivity 方法
startActivity(intent, optsBundle);
} finally {
StrictMode.setVmPolicy(oldPolicy);
}
} else {
launcherApps.startActivityForProfile(intent.getComponent(), user,
intent.getSourceBounds(), optsBundle);
}
return true;
} catch (SecurityException e) {
...
}
return false;
}
2.Activity启动部分(接下来会用到最开始导入的源码)
2.1 Activity.startActivityForResult
startactivity的几种重载方法都会调用startactivityForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
// mParent 代表的是ActivityGroup(api13废弃),是当前 Activity 的父类,此时条件成立
if (mParent == null) {
// 调用 Instrumentation 的 execStartActivity 方法
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this,
mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
...
} else {
...
}
}
2.2 Instrumentation.execStartActivity
路径: Sdk/sources/android-28/android/app/Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
// 获取 AMS 的代理对象并调用其 startActivity 方法
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
到这里可能会有些懵了,因为获取代理方法的代码和艺术探索里面的api21的有些不同,不过呢,查看ActivityManagerNative类的注释呢可以发现 @deprecated use IActivityManager.Stub.asInterface instead,在api28中由于还是在Launcher进程中,所以呢,这里asInterface获取到的就是AMS的代理对象。
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
2.3ActivityManagerService.startactivity()
接着我们回到startactivity,现在的话就是调用的AMS的startactivity。其中又调用的startActivityAsUser方法,在这个方法里面,和api21的有所区别,api21是mStackSupervisor的.startActivityMaywait.startActivityMayWait,这里改成了变成了构建者模式,不过这个mActivityStartController的构造方法里面也能发现mStackSupervisor的踪迹
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
构造者模式最后调用的 .execute()方法里面调用了startActivityMayWait。
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return
//这里调用startActivityMayWait
startActivityMayWait(mRequest.caller, ...
} else {
return startActivity(mRequest.caller, ...
}
} finally {
onExecutionComplete();
}
}
然后在startActivityMayWait中调用了startActivity,其中又调用了一次startActivity,其中的处理过程很比较繁琐,最后会走到ActivityStackSupervisor的resumeFocusedStackTopActivityLocked,然后到ActivityStack
2.4 ActivityStack.resumeTopActivityUncheckedLocked
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;
result = resumeTopActivityInnerLocked(prev, options); ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
2.5 resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (){
try {
} catch (Exception e) {
// Whoops, need to restart this activity!
mStackSupervisor.startSpecificActivityLocked(next, true, false);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
}
else {
// Whoops, need to restart this activity!
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
中间有很多情况的判断,总之就是需要启动的activity没启动的话,就调用StackSupervisor.startSpecificActivityLocked
2.6 StackSupervisor.startSpecificActivityLocked
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity ’s application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
getLaunchTimeTracker().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
这个ProcessRecord类app代表有关当前正在运行的特定进程的完整信息。
方法中先判断App是否启动,如果启动则执行realStartActivityLocked。如果未启动则调用ActivityManagerService.startProcessLocked方法启动App。
判断条件中的app.thread是interface IApplicationThread extends IInterface,因为继承自IInterface,所以他是一个Binder类型的接口。这个先放着,先看realStartActivityLocked方法。
2.7 StackSupervisor.realStartActivityLocked
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
...
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
在scheduleTransaction中会执行LaunchActivityItem.execute
2.8 LaunchActivityItem.execute
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
client是ClientTransactionHandler类,而这个类是抽象类,实现类是ActivityThread。
2.9 ActivityThread.handleLaunchActivity
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
return a;
}
这里ruturn了activity,说明这里完成了activity的创建。接下来看performLaunchActivity
2.10 ActivityThread.performLaunchActivity
注释中注明这里是活动启动的核心实现,那我们就仔细点分析下。 该方法主要做了这些事情。
- 从ActivityClientRecord获取带启动activity的信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
- mInstrumentation.newActivity方法实用类加载器创建Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
- makeApplication创建Application,如果Application已经创建过,就不会再创建,说明一个应用只有一个Application(多进程情况除外)。Application穿件完毕后,会调用instrumentation.callApplicationOnCreate(app),这会调用Applicaition的onCreate方法。
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
- 创建Contextimpl并通过activity.attach进行数据初始化
ContextImpl appContext = createBaseContextForActivity(r);
appContext.setOuterContext(activity);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
- 调用mInstrumentation.callActivityOnCreate,这个会调用activity的onCreate,至此点击app图标后activity的启动流程完毕
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
巨人的肩膀
《Android艺术开发探索》
虽然说Android版本不同,有些许差别,但是没有书的话,真的会迷失在各种调用里面,无法自拔
Android四大组件之Activity--应用进程与系统进程的通信
总结
其中还有一些部分没有分析完,activity第一次启动的进程创建部分还有和AMS通信的部分,还有详细的时序图,这个就先缓缓,Part2再写吧。
如果有错误的话,可以评论指出。如果觉得文章还不错,帮忙点个赞。