因为工作中经常要用到应用的启动流程,而网上和书本上大部分都是Android5.0和6.0的文章,有些部分Android7.0又做了修改,故本篇文章主要是整理以往大牛们在Android5.0、Android6.0的基础上对Android7.0点击Launcher到应用启动完成的一个大体流程,用于工作和大家参考,如有不足之处,欢迎指正。
当点击桌面的应用图标后,会触发Launcher3的Launcher.java中的onClick(View v)方法执行,一系列判断后将点击的View作为参数,调用startAppShortcutOrInfoActivity(v),
在startAppShortcutOrInfoActivity(v)中,根据传入参数View v的v.getTag()方法得到被点击应用图标的ShortcutInfo,然后得到Intent数据。
通过final Intent intent = ((ShortcutInfo) tag).intent语句得到数据,有了一个应用的Intent就可以启动一个应用了。
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);
}
}
}
@Thunk void startAppShortcutOrInfoActivity(View v) {
Object tag = v.getTag();
final ShortcutInfo shortcut;
final Intent intent;
if (tag instanceof ShortcutInfo) {
shortcut = (ShortcutInfo) tag;
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");
}
boolean success = startActivitySafely(v, intent, tag);
...
}
接着调用了startActivitySafely(v, intent, tag),这里调用了startActivity(v, intent, tag),参数中含有intent,intent中包含了action、category等信息。
public boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
...
try {
success = startActivity(v, intent, tag);
} catch (ActivityNotFoundException e) {
if (v instanceof TextView){
return success;
}
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
}
return success;
}
Launcher继承于Activity类,在startActivity(v, intent, tag)中调用了重写的startActivity(Intent intent, @Nullable Bundle options),因此,这里就调用了Activity.startActivity方法;
在startActivity(intent, optsBundle)中参数optsBundle包含了应用启动动画的坐标,width和height。
private boolean startActivity(View v, Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
if (user.equals(UserHandleCompat.myUserHandle())) {
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
try {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().build());
startActivity(intent, optsBundle);
} finally {
StrictMode.setVmPolicy(oldPolicy);
}
}
...
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
在Activity.startActivity方法中又调用了Activity.startActivityForResult方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
...
}
...
}
这里的mInstrumentation是Activity类的成员变量,它的类型是Intrumentation,定义在Instrumentation.java文件中,它用来监控应用程序和系统的交互。
这里的mMainThread也是Activity类的成员变量,它的类型是ActivityThread,它代表的是应用程序的主线程。这里通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,它是一个Binder对象,ActivityManagerService会使用它来和ActivityThread来进行进程间通信,mMainThread代表的是Launcher应用程序运行的进程。
这里的mToken也是Activity类的成员变量,它是一个Binder对象的远程接口。
接下来调用了Instrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options)
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.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;
}
可以看出,启动Activity真正的实现由ActivityManagerNative.getDefault()的.startActivity方法执行。
这里的ActivityManagerNative.getDefault()返回的是ActivityManagerService的一个代理类ActivityManagerProxy。
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
这里的参数比较多,我们先整理一下。从上面的调用可以知道,这里的参数resolvedType、grantedUriPermissions和resultWho均为null;参数caller为ApplicationThread类型的Binder实体;参数resultTo为一个Binder实体的远程接口,我们先不关注它;参数grantedMode为0,我们也先不关注它;参数requestCode为-1;参数onlyIfNeeded和debug均空false。
由于ActivityManagerProxy是一个代理类,上面是通过IPC的Binder联系到ActivityManagerService,最后会调用ActivityManagerService的startActivity方法。
AMS(ActivityManagerServie)中提供了几个借口来启动Activity,但是,他们都会调用到ActivityStarter类的startActivityMayWait()方法,Android7.0以前是ActivityStackSupervisor类;
接下来以上面调用的startActivity方法继续分析,startActivity方法调用了startActivityAsUser方法,代码如下
@Override
public int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, St