Android Activity 启动过程详解(上)
- 你想要找的activity知识都在这里了
- 一份超详细的Fragment知识总结
- FragmentManager与FragmentTransaction底层实现
- Android 系统启动过程详解
- Activity 启动过程详解(上)
App 启动 Activity 时,需要向系统发送请求启动信号,处理该请求的服务就是 AMS (ActivityManagerService),这个操作是跨进程的。想想 上一篇 说的, init 解析 rc 脚本启动 Zygote,其所在进程 app_process (后改名 zygote )的 ZygoteInit 通过 forkSystemServer 创建一个进程,来启动各种系统服务,这里就包含 AMS;而 ZygoteInit 又通过 forkAndSpecialize 为每个新启动的应用程序生成自己独立的进程,并在 handleChildProc 方法中运行应用程序本身的代码,所以说启动 Activity 的过程是跨进程的。
我们通过 startActivity 方法来启动一个 Activity ,这里以显示调用为例:
Intent intent = new Intent(this, DemoActivity.class);
startActivity(intent);
① android.app.Activity#startActivity,startActivity 有几种重载方法,但都会调用 startActivityForResult 方法。
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
② android.app.Activity#startActivity(Intent intent, @Nullable Bundle options)
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
③ android.app.Activity#startActivityForResult , 这里只需要关注 mParent == null 的即可,mParent 代表的是 ActivityGroup, ActivityGroup 开始被用来在一个界面中嵌入多个子 Activity,但在 API 13 被废弃了,被 Fragment 代替。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
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());
}
...
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
...
}
}
④ android.app.Instrumentation#execStartActivity ,之后就会跨进程调用 ActivityManagerService 的 startActivity 方法了(在 android10 内,AMS 的 startActivity 又会调用 mActivityTaskManager.startActivity ,将启动 Activity 的任务交给 ATMS),具体代码实现见下。 checkStartActivityResult 方法的作用是检查启动 Activity 的结果,当无法正常启动一个 Activity 时,会抛出异常信息,这就不再细看了。
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.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;
}
⑤ 接着分析上面的 ActivityTaskManager.getService() 方法,其中 Singleton 是单例模式类,当调用 get() 方法时,会进行内部判断:如果该对象已存在,则直接返回现有值,否则通过调用 create() 方法创建并返回 IActivityTaskManager 对象 。
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
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);
}
};
⑥ 在这里是通过 ServiceManager.getService 来获取 ActivityManagerService 的 IBinder 对象的,当其中 sCache 用于记录 getService 的历史查询结果,getService 每次都会首先在这里翻阅记录,以加快查询速度,如果不存在,则通过 rawGetService 方法内的 getIServiceManager().getService(name) 向 SM 发起查询。
@UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IBinder rawGetService(String name) throws RemoteException {
final long start = sStatLogger.getTime();
final IBinder binder = getIServiceManager().getService(name);
...
return binder;
}
⑦ getIServiceManager 方法首先会判断 sServiceManager 是否为空,防止多次重复操作。之后通过 ServiceManagerNative.asInterface 来获取一个 IServiceManager 对象。这个 IServiceManager 对象就是负责与 Binder 驱动通信的 SM 代理 ServiceManagerProxy,具体代码见下:
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
⑧ asInterface 方法负责将 Binder 对象转换成 IServiceManager,并在必要的时候创建 ServiceManagerProxy,这就是我们 ServiceManager 的代理,来负责与 Binder 驱动通信。
@UnsupportedAppUsage
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
⑨ 在回到上面的 rawGetService 方法内的 getIServiceManager().getService(name) 方法,通过 SM 代理的 getService 方法,首先通过 Parcel 打包数据;接着通过 IBinder 的 transact 将请求发送出去,具体会通过 jni 调用对应的 BpBinder,进而使用 ProcessState 和 IPCThreadState 的相关接口,完成与 SM 的通信;之后就可以获取到结果了(这里的 IBinder 就是 AMS 的IBinder 对象了),因为这里是一种阻塞式函数调用,因为是进程间通信,结果并不会马上就能获取到,所以 Binder 驱动会先将调用者线程挂起,直到有了结果才会将它唤醒。
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
@UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
...
@UnsupportedAppUsage
private IBinder mRemote;
}
⑩ allowBlocking 的作用是判断当前 IBinder 是否为 BinderProxy,是则改变 mWarnOnBlocking 标志位。
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
}
⑪ 接下来我们就来看 AMS 内 startActivity 是如何实现的呢?能够看到 AMS 将实现委托给了 ATMS,这样做的好处是职责变得更单一了,避免 AMS 过于臃肿,符合 OO 设计原则。
@Override
public int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
}
ActivityTaskManagerService 的 startActivity 方法又会调用 startActivityAsUser 方法:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
⑫ 这是 startActivityAsUser 的方法:其中 getActivityStartController() 方法会返回当前持有的 ActivityStartController 对象,obtainStarter 方法会调用 ActivityStarter 内部类 DefaultFactory 的 .obtain() 方法创建 ActivityStarter 对象,随后调用ActivityStarter 的 setIntent(intent).setReason(reason) 等的属性赋值,最后调用 ActivityStarter 的 execute 方法,这里就不展示代码了。
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) {
...
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
⑬ 其中 setMayWait 方法,会将 ActivityStarter 内部类 Request 的 mayWait 字段设置为 true :
ActivityStarter setMayWait(int userId) {
mRequest.mayWait = true;
mRequest.userId = userId;
return this;
}
⑭ checkTargetUser 方法内,其中 validateIncomingUser 为 true, targetUserId 是当前调用者的用户ID 值,由 UserHandle.getCallingUserId() Binder 机制获取,UserHandle 是 aidl 文件,handleIncomingUser 会检查调用者是否有权利执行这一操作。
int checkTargetUser(int targetUserId, boolean validateIncomingUser,
int realCallingPid, int realCallingUid, String reason) {
if (validateIncomingUser) {
return mService.handleIncomingUser(
realCallingPid, realCallingUid, targetUserId, reason);
} else {
mService.mAmInternal.ensureNotSpecialUser(targetUserId);
return targetUserId;
}
}
⑮ 这是 ActivityStarter 的 execute 的方法,会调用 startActivityMayWait 方法,mRequest.mayWait 是前面提到的启动参数。
int execute() {
try {
if (mRequest.mayWait) {
return startActivityMayWait(...);
} else {
...
} finally {
onExecutionComplete();
}
}
⑯ 在 startActivityMayWait 方法内,会调用 26 个参数的 startActivity 方法,接着会调用 10 个参数的 startActivity 方法,接着会调用 startActivityUnchecked 方法,然后会调用 mTargetStack.startActivityLocked 方法,这样就将 Activity 的启动过程转移到了 ActivityStack 。
Todo: startActivityLocked 逻辑复杂,下篇会结合启动模式,来梳理下 AMS 是如何恢复上层 Activity 和 新旧 Activity 切换,并通知给调用者的。
参考
1、林学森,深入理解 Android 内核设计思想:人民邮电出版社
2、任玉刚,Android 开发艺术探索:中国工信出版集团
本文地址:https://blog.csdn.net/MingJieZuo/article/details/108532581
上一篇: 网络扫描仪无法使用 总是报错怎么办?
推荐阅读
-
Android中Activity启动默认不显示输入法解决方法
-
Android 两种启动模式的实例详解
-
Android Service的启动过程分析
-
Android开机自启动程序详解
-
Android-----Intent中通过startActivity(Intent intent )显式启动新的Activity
-
解析Android中Service的启动过程时序图
-
Android中点击按钮启动另一个Activity以及Activity之间传值
-
Android中方法数超限问题与启动优化详解
-
Android基础之Fragment与Activity交互详解
-
16.Android-activity生命周期与启动模式