源码使用API 16进行分析
Demo
创建两个Activity用于源码分析:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.startactivitydemo">
...
<activity android:name=".TargetActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
MainActivity.java:
...
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, TargetActivity.class));
}
});
}
}
TargetActivity.java:
...
public class TargetActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_target);
}
}
...
向AMS发送startActivity请求
App启动Activity时,需要向系统发送请求启动信号,处理该请求的服务称为AMS(ActivityManagerService)。这里的跨进程操作发生在App进程和系统进程之间。
从onClick中的startActivity开始分析:
android.app.Activity#startActivity(android.content.Intent):
@Override
public void startActivity(Intent intent) {
startActivity(intent, null);
}
android.app.Activity#startActivity(android.content.Intent, android.os.Bundle)
@Override
public void startActivity(Intent intent, Bundle options) {
if (options != null) {
...
} else {
startActivityForResult(intent, -1);
}
}
android.app.Activity#startActivityForResult(android.content.Intent, int):
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
android.app.Activity#startActivityForResult(android.content.Intent, int, android.os.Bundle):
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
...
//mParent的使用场景很古老了,通常都是null
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
//ar始终是null,详见下文
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
} else {
...
}
android.app.Instrumentation#execStartActivity(android.content.Context, android.os.IBinder, android.os.IBinder, android.app.Activity, android.content.Intent, int, android.os.Bundle):
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
//InstrumentationTest相关逻辑
...
}
try {
...
//这里向AMS发送启动信号
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, null, options);
//处理AMS返回值
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
跨进程发生在ActivityManagerNative.getDefault().startActivity(...)中,紧接着会对跨进程的返回值做处理。不考虑InstrumentationTest逻辑,该函数始终返回null。
android.app.Instrumentation#checkStartActivityResult:
static void checkStartActivityResult(int res, Object intent) {
if (res >= ActivityManager.START_SUCCESS) {
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
ActivityManager.START_SUCCESS的值是0,App进程无需处理返回值。其他的情况则依据返回值抛出对应的异常。当启动一个没有在xml中声明的,或者无权限启动的Activity,App会Crash,便是在这里产生的。
AMS跨进程发送信号
下面分析:ActivityManagerNative.getDefault().startActivity(...):
...
static public IActivityManager getDefault() {
return gDefault.get();
}
...
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
//通过系统ServiceManager获取AMS句柄
IBinder b = ServiceManager.getService("activity");
...
//将句柄转换成IActivityManager接口,实际上是android.app.ActivityManagerProxy实例
IActivityManager am = asInterface(b);
...
return am;
}
};
可以看到ActivityManagerNative.getDefault()是个单例,返回值是从ServiceManager.getService("activity")中获取的。asInterface会检查Binder是否跨进程了,若跨进程了,会把IBinder封装成android.app.ActivityManagerProxy。Binder是Android实现跨进程的主要方式。
因此会调用到android.app.ActivityManagerProxy#startActivity中:
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, String profileFile,
ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
//Parcel data写入要传递给AMS的数据 start
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
data.writeString(profileFile);
if (profileFd != null) {
data.writeInt(1);
profileFd.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);
}
//Parcel data写入要传递给AMS的数据 end
//跨进程
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
//reply是AMS所在进程返回的数据,检查是否需要处理异常
reply.readException();
//读取返回结果
int result = reply.readInt();
//回收Parcel
reply.recycle();
data.recycle();
return result;
}
该函数向AMS发送了跨进程数据,且获得了AMS的返回数据,一次握手就完成了。Parcel是配合Binder使用的,用于承载跨进程数据结构的,是Native实现。
startActivity跨进程传递的参数
android.app.ActivityManagerProxy#startActivity中的参数较多,这里单独分析一下:
- caller:android.app.ActivityThread.ApplicationThread对象,用于区分请求方进程,当前的请求方就是当前APP进程。
- intent:启动意图,表示要启动什么,怎么启动
- resolvedType::Intent中包含的type,和当前场景无关
- resultTo:android.app.Activity#mToken传递过来的,用于区分发起请求的Activity,也可以理解为:AMS要返回数据的接收方
- resultWho:场景无关的参数,可不关心
- requestCode:startActivityForResult时的requestCode,当前场景是-1,场景无关
- startFlags:当前传入的0,场景无关
- profileFile:当前传入null,场景无关
- profileFd:当前传入null,场景无关
- options:启动Activity的一些其他参数,当前场景是null,场景无关
- START_ACTIVITY_TRANSACTION:AMS接收的操作有很多,它标识了当前是startActivity操作
核心参数是caller、START_ACTIVITY_TRANSACTION和intent、resultTo,分别阐述了:
- 谁发起了请求?
- 要请求什么?
- 请求返回数据给谁?
总结
startActivity由App进程中发起,发向AMS,第一次握手的由此开始。App进程侧逻辑简单,系统进程中AMS的处理才是主角。