什么是 AMS
AMS(ActivityManagerService)主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作。通常情况下我们不会把 AMS 单独的拆分出来讲解,因为 AMS 需要通过 PMS(PackageManagerService)获取信息。
下面的节点在讲解 AMS 时会穿插 PMS(PackageManagerService) 相关的内容,关于 PMS 的原理具体可以查看 Android PMS 原理,这里不会过多赘述。
没有 PMS 和 AMS 会发生什么
在 Android PMS 原理 可以了解到,PMS 在手机开机的时候会运行解析所有 apk 的 AndroidManifest.xml,将每个 apk 信息存到内存中,并提供查询接口,可以认为 PMS 充当着包信息缓存的作用。
而 AMS 其中一个职责是管理调度 Activity,需要启动某个 Activity 时都会先找 PMS 查询要跳转的 Activity 信息再处理后续一系列的操作。
我们可以思考一个问题:为什么 Android 要提供 AMS 和 PMS?如果没有 AMS 和 PMS 会发生什么?
假设现在要启动某个进程的 Activity,简单梳理下会经历五个步骤:
-
遍历 data/app 目录获取到该目录下所有 apk 文件
-
解压所有 apk 获取 AndroidManifest.xml
-
dom 解析 AndroidManifest.xml 解析出 Activity 标签生成对应数据类存到内存
-
从内存查找到要跳转的 Activity 信息,获取到 Activity 全类名,反射构建对象
-
依次执行 Activity 的生命周期
如果每次进程调度都要这么处理,可以想象效率是很低的。
为了能快速的定位到要跳转的 Activity,前面的三个步骤将会交由 PMS,PMS 提前在开机启动时先解析完成存到内存,这样当 AMS 需要跳转某个 Activity 时,直接从 PMS 存储到内存的数据去提取信息,就能更快的完成操作。
AMS 从 PMS 拿到创建 Activity 的信息创建出来后,就会需要考虑 Activity 的生命周期,总不能 Activity 一退出就销毁,所以 AMS 就需要管理创建出来的 Activity 的生命周期。每个应用每个进程都有自己的 ActivityThread,所以 AMS 也需要一个缓存中心管理 Activity 的生命周期,就是由 ActivityThread 充当这个角色(更具体说是 ActivityThread 下的 mActivities 变量)。
ActivityThread.java
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
// 创建 Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
...
try {
...
if (activity != null) {
...
r.activity = activity; // ActivityClientRecord 记录 Activity
}
mActivities.put(r.token, r); // 将创建的 Activity 存储到 map
} catch (SuperNotCalledException e) {
...
}
...
return activity;
}
public static final class ActivityClientRecord {
...
Activity activity; // 持有 Activity
...
}
可以看到 ActivityThread 的源码中有一个 mActivities 的成员变量,ActivityClientRecord 是持有 Activity 的引用。在后续的 performXxxActivity() 等处理生命周期的方法中都会用 mActivities 管理。
App 的启动过程
在 Android 无论是启动一个应用还是启动应用内的 Activity,都是调用的 startActivity() 方法。总体会经历三个步骤:
-
告知 AMS 要启动一个指定的 Activity
-
AMS 从 PMS 查找要启动的 Activity 信息
-
启动指定 Activity
接下来我们具体通过源码(API 28)分析 startActivity() 的整个过程。
Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@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);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
...
// 委托给 Instrumentation
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
....
}
...
}
当我们调用 startActivity() 时,最终都会调用到 startActivityForResult(),应用上层对接 Android 核心服务会委托给 Instrumentation。Instrumentation 是专门负责 Application 和 Activity 的相关所有活动处理,就是和 AMS 通信会委托给 Instrumentation。
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
// 找到 AMS 告知要启动 Activity
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
...
}
...
}
Instrumentation 会告知 AMS 要启动一个 Activity。
需要注意的是,在这里不同系统版本的源码处理也不一样,在 9.0 之前是使用 AMS,9.0 之后是使用 ATMS(ActivityTaskManagerService):
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
// 9.0 之后会通过 ATMS 告知要启动 Activity
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(tho.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
...
}
...
}
目前源码是以 API 28 分析,所以我们回到 API 28 的源码分析。
ActivityManager.getService().startActivity() 这句代码可以拆分成两部分:ActivityManager.getService() 和 startActivity()。
我们先看 ActivityManager.getService():
ActivityManager.java
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
// 通过 ServiceManager 获取 AMS 服务
// IActivityManager 是 binder 代理
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
ActivityManager.getService() 会获取 IActivityManager,它是一个 binder 代理对象。从代码可以看出,当使用 ActivityManager.getService() 对象调用方法时,实际上已经在做跨进程通信,由 binder 代理对象和 AMS 通信,通信所在的进程是 system_server。同时这里也是一个很好的 hook 点。
到这一步为止已经完成了告知 AMS 要启动 Activity 的第一个步骤。
我们继续分析源码。
ActivityManagerService.java
@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) {
// 有多个 startActivityAsUser() 重载方法,为了方便查看省略了多个方法调用
return startActivityAsUser(...);
}
public final int startActivityAsUser(...) {
...
// mActivityStartController.obtainStarter 返回 ActivityStarter 对象
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();
}
使用 AMS 调用 startActivity() 方法,主要是找到 mActivityStartController.obtainStarter() 获取到 ActivityStarter 对象,很明显使用了构建者模式配置相关参数,重点在 execute() 方法。
按照我们一开始设定的步骤,第二步是 AMS 要找到 PMS 获取跳转 Activity 相关的信息,那么 AMS 是怎么和 PMS 通信的?
ActivityStarter.java
int execute() {
try {
if (mRequest.mayWait) {
return startActivityMayWait(...);
} else {
return startActivity(...);
}
} finally {
...
}
}
private int startActivityMayWait(...) {
...
// AMS 和 PMS 产生关联,从 PMS 获取信息
ResolveInfo rInfo = mSupervisor.resolveIntent(...);
...
return res;
}
ActivityStackSupervisor.java
ResolveInfo resolveIntent(...) {
// mService 是 AMS
synchronized (mService) {
...
try {
// mService.getPackageManagerInternalLocked() 返回 PackageManagerInternalImpl
return mService.getPackageManagerInternalLocked().resolveIntent(...);
} finally {
....
}
}
...
}
ActivityManagerService.java
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
}
return mPackageManagerInt;
}
PackageManagerService.java
// PackageManagerInternalImpl 的作用是,它作为内部类能拿到外部类的引用
// 所以可以充当 AMS 和 PMS 的桥梁,让 AMS 能获取到 PMS
private class PackageManagerInternalImpl extends PackageManagerInternal {
...
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId, boolean resolveForStart, int filterCallingUid) {
// 作为桥梁外部调用相关方法时都转发给 PMS
// ResolveInfo 持有 ActivityInfo、serviceInfo 等信息
return resolveIntentInternal(
intent, resolvedType, flags, userId, resolveForStart, filterCallingUid);
}
...
}
ResolveInfo.java
public class ResolveInfo implements Parcelable {
public ActivityInfo activityInfo;
public ServiceInfo serviceInfo;
public ProviderInfo providerInfo;
...
}
AMS 和 PMS 通信获取的是 ResolveInfo 包装对象,它可以存储 ActivityInfo、ServiceInfo 等信息,不直接返回 ActivityInfo 的原因应该是要启动 Service 等其他组件时可以复用同一套逻辑,因为获取的方式基本是相同的。
AMS 和 PMS 的通信也不是直接通信,而是通过 PMS 的 PackageManagerInternalImpl 内部类作为桥梁,内部类持有外部类的引用,所以 PackageManagerInternalImpl 可以直接访问 PMS。这样的做法既能实现功能,又能降低 AMS 和 PMS 之间的耦合,限制公开的 api 访问。
到这里已经完成第二步从 PMS 获取到要启动的 Activity 信息,就可以开始第三步启动 Activity。
ActivityStarter.java
private int startActivityMayWait(...) {
...
// AMS 和 PMS 产生关联,从 PMS 获取信息
ResolveInfo rInfo = mSupervisor.resolveIntent(...);
...
// 从封装的 ResolveInfo 获取到要跳转的 ActivityInfo 信息
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
...
// 开始启动 Activity
int res = startActivity(...);
...
return res;
}
private int startActivity(...) {
int result = START_CANCELED;
try {
...
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
} finally {
...
}
...
}
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
mSuperVisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
...
}
ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!readyToResume()) {
return false;
}
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || !r.isState(RESUMED)) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
try {
...
result = resumeTopActivityInnerLocked(prev, options);
...
}
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
mStackSupervisor.startSpecificActivityLocked(next, true, false);
...
}
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
...
// 先判断要启动的 Activity 进程是否已经存在
if (app != null && app.thread != null) {
try {
...
// 进程已经存在,启动 Activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
...
}
}
// 如果进程不存在,AMS 通知 zygote 启动进程,最终反射调用 ActivityThread.main()
// 有多个 startProcessLocked() 重载方法,为了方便查看省略了多个方法调用
mService.startProcessLocked(...);
}
ActivityManagerService.java
private boolean startProcessLocked(...) {
...
// 其中一个 startProcessLocked() 提供了要启动的进程为 ActivityThread
final String entryPoint = "android.app.ActivityThread";
... // 省略其他 startProcessLocked() 调用
if (mConstants.FLAG_PROCESS_START_ASYNC) {
...
// 传入要启动的进程
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, ...)
}
...
}
private ProcessStartResult startProcess(String entryPoint, ...) {
try {
...
startResult = Process.start(entryPoint, ...);
...
} finally {
...
}
}
Process.java
public static final ProcessStartResult start(final String processClass, ...) {
return zygoteProcess.start(processClass, ...);
}
按上面源码的分析,启动 Activity 前其实还需要再细分拆成两个处理:
-
要启动的 Activity 所在进程如果没有创建,AMS 会通知 Zygote fork 进程,最终会反射调用 ActivityThread 的 main() 方法,再走后续的 Activity 创建及后续生命周期流程
-
进程已经创建,realStartActivityLocked() 创建 Activity 及后续生命周期流程
Activity 的启动涉及到了生命周期,AMS 既然是管理调度 Activity 的服务,那就需要能和启动的 Activity 有所关联。AMS 是用什么方式管理 Activity 的生命周期的?
ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();
public static void main(String[] args) {
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
}
private void attach(boolean system, long startSeq) {
...
if (!system) {
...
final IActivityManager mgr = ActivityManager.getService();
try {
// 将 ApplicationThread 给到 AMS 作为句柄管理
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
...
}
...
}
...
}
private class ApplicationThread extends IApplicationThread.Stub {
// AMS 下发管理四大组件,将处理转发给变量名为 mH 的 Handler
...
@Override
public void scheduleTransaction(ClientTransaction transaction) {
ActivityThread.this.scheduleTransaction(transaction);
}
}
class H extends Handler {
// Activity 生命周期等消息的处理
...
}
在 ActivityThread 的 main() 方法,可以从源码看到创建了一个 ApplicationThread,然后将这个对象给到了 AMS,Activity 生命周期其实就是使用的 ApplicationThread 作为句柄交给 AMS,AMS 就可以通过这个句柄下发管理 Activity 的生命周期;同样的 AMS 也通过 ApplicationThread 管理四大组件和进程的其他处理,在 ApplicationThread 由 Handler 转发消息驱动处理。
启动 Activity 之前,还需要先启动创建 Application。AMS 获取 ApplicationThread 调用了 attachApplication():
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
...
}
}
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (app.isolatedEntryPoint != null) {
...
} else if (app.instr != null) {
// 通过 ApplicationThread 和 App 进程通信
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
} else {
...
}
...
if (normalMode) {
try {
// 创建完 Application 后走 Activity 生命周期流程
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
}
ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
public final void bindApplication(...) {
...
// 在 ActivityThread 也是获取的 AMS 数据创建 application
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
sendMessage(H.BIND_APPLICATION, data); // 消息驱动发消息给到 Handler
}
}
class H extends Handler {
public static final int BIND_APPLICATION = 110;
...
public void handleMessage(Message msg) {
switch (mssg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData) msg.obj;
handleBindApplication(data);
break;
...
}
}
}
private void handleBindApplication(AppBindData data) {
...
// 反射创建 Instrumentation 负责管理 application 和 activity 相关所有活动处理
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
...
}
...
try {
// info 是 LoadedApk,反射创建 application
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
...
}
public final class LoadedApk {
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
// 创建 application
Application app = null;
try {
ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
} catch (Exception e) {
...
}
...
if (instrumentation != null) {
try {
// 调用 application.onCreate()
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
...
}
}
attachApplication() 实际上做了三件事情:
-
创建 Instrumentation,负责管理 Application 和 Activity 相关所有活动处理
-
创建 Application
-
创建 Activity 开始走生命周期流程
在上面我们有提到,Activity 的创建和后续生命周期流程是从 realStartActivityLocked() 方法开始的。让我们继续分析 Activity 的创建过程。
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
final ActivityStackSupervisor mStackSupervisor;
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
...
}
}
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (mStackSupervisor.attachApplicationLocked(app)) {
}
...
}
}
ActivityStackSupervisor.java
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
RecentTasks.Callbacks {
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
...
if (realStartActivityLocked(activity, app, top == activity) {
}
...
}
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// app.thread 是 ApplicationThread
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(...));
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
// 执行完 LaunchActivityItem 事务后要处在的生命周期状态
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// mService 是 AMS
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
}
ClientTransaction 是客户端事务管理类,通过不同的状态 LaunchActivityItem、ResumeActivityItem、PauseActivityItem 等,分别代表不同的 Activity 生命周期,以状态的方式加以管理。
在上面有提到 AMS 管理 Activity 的生命周期是通过 ApplicationThread 句柄,在创建 ClientTransaction.obtain() 也能看到是传入了 ApplicationThread 下发的生命周期处理:
ClientTransaction.java
public class ClientTransaction implements Parcelable, ObjectPoolItem {
private IApplicationThread mClient;
// 记录事务结束后要处在的生命周期状态,后面会用到
public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
mLifecycleStateRequest = stateRequest;
}
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
instance.mClient = client; // 存储的 ApplicationThread
instance.mActivityToken = activityToken;
return instance;
}
}
继续分析 mService.getLifecycleManager().scheduleTransaction(clientTransaction) 做了什么事情:
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
ClientLifecycleManager getLifecycleManager() { return mLifecycleManager; }
}
class ClientLifecycleManager {
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
...
}
}
ClientTransaction.java
public class ClientTransaction implements Parcelable, ObjectPoolItem {
private IApplicationThread mClient;
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this); // 拿着 ApplicationThread 下发通知
}
}
ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
// 在 ActivityThread 是找不到 scheduleTransaction 方法的
// 而是在 ActivityThread 的父类 ClientTransactionHandler 调用
ActivityThread.this.scheduleTransaction(transaction);
}
}
AMS 就是拿着 ApplicationThread 句柄告知 ActivityThread 要创建 Activity,在 ActivityThread 的源码中你会发现 ActivityThread.this.scheduleTransaction() 代码没有找到,实际上它是放在了 ActivityThread 继承的父类 ClientTransactionHandler。
ClientTransactionHandler.java
public abstract class ClientTransactionHandler {
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
// 通过 Handler 发了一条消息
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
}
public final class ActivityThread extends ClientTransactionHandler {
// TransactionExecutor的构造传入的 ActivityThread
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
class H extends Handler {
public static final int EXECUTE_TRANSACTION = 159;
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
}
}
}
}
TransactionExecutor.java
public class TransactionExecutor {
// ActivityThread
private ClientTransactionHandler mTransactionHandler;
public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {
mTransactionHandler = clientTransactionHandler;
}
public void execute(ClientTransaction transaction) {
...
executeCallbacks(transaction);
executeLifecycleState(transaction);
...
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
...
// 执行事务,这里是设置了 LaunchActivityItem
item.execute(mTransactionHandler, token, mPendingActions);
...
}
}
private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
...
// 执行完事务后处在的生命周期状态,这里是 ResumeActivityItem
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
}
}
在 Handler 接收到消息后启动事务的处理,处理事物交由 TransactionExecutor 负责,主要看两个函数:
-
executeCallbacks():执行具体的事务,例如 LaunchActivityItem
-
executeLifecycleState():执行事务后要处在哪个状态,例如 ResumeActivityItem、PauseActivityItem
LaunchActivityItem.java
public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
// 最终到 ActivityThread 开始创建 Activity
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
}
ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler {
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// 通过 Instrumentation 反射创建 Activity
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
}
...
// 调用 Activity 生命周期 onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
简单总结下 realStartActivityLocked() 做了什么事情:
创建了 ClientTransaction 处理生命周期的执行事务,可以认为它是 AMS 具体处理 Activity 生命周期的执行类。不同的生命周期用不同的状态表示, LaunchActivityItem 表示的 onCreate() 的生命周期,还有 ResumeActivityItem 表示的 onResume() 的生命周期,事务具体执行最终都会下发到对应的 ActivityLifecycleItem,由这些状态类执行回调 Activity 的生命周期。
至此,App 的启动流程就分析到这里。
总结下整体 App 的启动过程:
-
调用 startActivity() 时,实际会走到 Instrumentation,由它与 AMS 通信
-
Instrumentation 会找 ServiceManager 获取 AMS(实际是获取 binder 代理)调用 startActivity()。在 9.0 之前是获取 AMS,9.0 之后是获取 ATMS
-
AMS 找到 PMS 获取启动的 Activity 信息
-
然后判断需要启动的 Activity 所在进程是否已存在,不存在 AMS 通过 socket 通知 Zygote fork 进程,然后反射调用 ActivityThread 的 main(),创建 Instrumentation、Application 和 Activity 以及走生命周期流程
-
如果需要启动的 Activity 所在进程已经存在,创建 Activity 以及走生命周期流程
具体流程如下:
hook 启动未在 AndroidManifest.xml 注册的界面
有关 AMS 的源码已经分析完毕,那么知道 AMS 的源码有哪些应用场景呢?
我们经常会在业务中遇到一种场景,如果用户未登陆就跳转到登陆界面,已登陆就跳转到其他界面,所以也就会出现类似这种写法:
if (isLogin) {
startActivity(new Intent(context, LoginActivity.class);
} else {
startActivity(new Intent(context, OtherActivity.class);
}
当项目有大量的地方需要判断登陆再跳转界面,后续如果有业务改动,比如跳转的登陆界面修改,这种硬编码的方式侵入性高,要修改的范围很广,并不利于维护。
或许你会说:我用隐式意图在 AndroidManifest.xml 定义 action,然后用常量类提供 action 统一管理不就行了:
AndroidManifest.xml
<manifest>
<application>
<activity name="LoginActivity">
<intent-filter>
<action name="android.intent.action.login" />
</intent-filter>
</activity>
</application>
</manifest>
public class Constants {
public static final String ACTION_LOGIN = "android.intent.action.login";
}
if (isLogin) {
startActivity(new Intent(context, Constants.ACTION_LOGIN);
} else {
startActivity(new Intent(context, OtherActivity.class);
}
那我再加一个条件:我想不在 AndroidManifest.xml 注册登陆界面想正常启动,能做到吗?
正常情况是不行的,但我们在熟悉了 AMS 和 PMS 的源码后,就能通过 hook 绕过系统检测正常启动一个 Activity。
hook 简单来说就是绕过系统处理,自己用不同的方式实现同样的效果,但这个过程还是要用到系统创建的一些信息帮助我们完成处理。
但是要使用 hook 一般有三个前提条件:
-
找到合适的 hook 点:在 Java 中一般是静态成员变量或成员方法,非静态成员变量是不能 hook 的,因为会借助反射获取 hook 点
-
hook 的兼容性:hook 会借助系统源码的 api,但不同版本的源码会存在不同的 hook 点,hook 方式也不一样
-
熟悉源码原理:保证系统流程正常情况能正确 hook 处理
根据一开始提到的每次跳转都要鉴权的案例,我们尝试用 hook 实现只在代码写具体业务跳转,自动完成没有登陆就跳转登陆界面,否则就跳转具体业务界面。demo 将在 API 28 的源码上实现。
要实现这个效果有两大难点:
-
不在 AndroidManifest.xml 注册界面,怎么绕过检查?
-
绕过检查后,又该怎么正常启动这个 Activity?
不在 AndroidManifest.xml 注册界面,在文章最开始有提到 AMS 的原理分析是离不开 PMS的,因为 AMS 在启动 Activity 过程中会找 PMS 拿 Activity 的信息,所以这个问题更具体说是如何绕过 PMS 的检查。
为了实现这个效果,hook 能做的就是将 startActivity() 拦截下来,替换掉携带着目标 Activity 的 Intent 信息,在原始数据保留的情况下增加额外的信息到 Intent。这样也就能在 PMS 的检查下流程正常执行。
那么合适的 hook 在哪里呢?Instrumentation 有一个和 AMS 通信的处理,我们要拿到 AMS 的 binder 代理,这里重新将源码贴出来:
ActivityManager.java
// 已经创建好的 IActivityManager,更具体说要拿到 mInstance,是一个很好的 hook 点
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;
}
};
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
hook 并不是完全要自己创建信息,而是要利用系统 api 或提前创建好的信息加以利用,mInstance 即 IActivityManager 是我们要用到的对象,要拦截它调用 startActivity() 时的处理,替换我们的 Intent,这需要用到动态代理。代码如下:
public class Hooker {
public void hook() throws Exception {
hookAms();
}
public void hookAms() throws Exception {
if (proxyActivity == null) {
throw new NullPointerException("proxyActivity is null");
}
Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
IActivityManagerSingletonField.setAccessible(true);
// 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);
Class SingletonClz = Class.forName("android.util.Singleton");
Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 拿到 ActivityManagerService 的 binder 代理
// 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);
Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
Object proxyIActivityManager = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
// 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
// 将 mInstance 的调用都跑我们的代理
mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
}
private class AmsInvocationHandler implements InvocationHandler {
private final Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 系统使用 mInstance 的调用都会走到代理
if ("startActivity".contains(method.getName())) {
Intent intent = null;
int index = 0;
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof Intent) {
intent = (Intent) args[i];
index = i;
break;
}
}
if (intent != null) {
Intent proxyIntent = new Intent();
ComponentName componentName = new ComponentName(context, proxyActivity);
proxyIntent.setComponent(componentName);
proxyIntent.putExtra("oldIntent", intent);
args[index] = proxyIntent; // 替换真实意图
}
}
return method.invoke(iActivityManagerObject, args);
}
}
}
绕过 PMS 的问题已经解决,接下来是第二个问题:怎么正常启动 Activity?
Activity 的创建和生命周期流程都是在 Handler 消息驱动下完成的,定位到具体源码是 ActivityThread 的 mH 成员变量:
ActivityThread.java
final H mH = new H();
class H extends Handler {
public static final int EXECUTE_TRANSACTION = 159;
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
}
}
}
很遗憾的是,不能在 ActivityThread 将 handleMessage() 的消息拦截下来。
实际上 Handler 已经为我们提供了 hook 点:
Handler.java
final Callback mCallback;
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果 mCallback 不为空,先处理 mCallback 的 handleMessage()
// 如果 mCallback 的 handleMessage() 返回 false,调用兜底的 handleMessage()
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以设置我们自己的 mCallback,这样就能在兜底的 handleMessage() 之前,提前将消息拦截处理,需要拦截的消息返回 true 不再传递,否则返回 false 按正常走不影响启动流程。
完整代码如下:
public class Hooker {
private final Context context;
private Class<?> proxyActivity;
public Hooker(@NonNull Context context) {
this.context = context;
}
public void setProxyActivity(@NonNull Class<?> proxyActivity) {
this.proxyActivity = proxyActivity;
}
public void hook() throws Exception {
hookAms();
hookSystemHandler();
}
public void hookAms() throws Exception {
if (proxyActivity == null) {
throw new NullPointerException("proxyActivity is null");
}
Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
IActivityManagerSingletonField.setAccessible(true);
// 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);
Class SingletonClz = Class.forName("android.util.Singleton");
Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 拿到 ActivityManagerService 的 binder 代理
// 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);
Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
Object proxyIActivityManager = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
// 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
// 将 mInstance 的调用都跑我们的代理
mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
}
public void hookSystemHandler() throws Exception {
Class ActivityThreadClz = Class.forName("android.app.ActivityThread");
Field field = ActivityThreadClz.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object ActivityThreadObj = field.get(null);
Field mHField = ActivityThreadClz.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mHObj = (Handler) mHField.get(ActivityThreadObj);
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
ProxyHandlerCallback proxyCallback = new ProxyHandlerCallback();
mCallbackField.set(mHObj, proxyCallback);
}
private class ProxyHandlerCallback implements Handler.Callback {
public static final int EXECUTE_TRANSACTION = 159;
@Override
public boolean handleMessage(Message msg) {
if (msg.what == EXECUTE_TRANSACTION) {
try {
Class<?> ClientTransactionClz = Class.forName("android.app.servertransaction.ClientTransaction");
if (!ClientTransactionClz.isInstance(msg.obj)) {
return false;
}
Class<?> LaunchActivityItemClz = Class.forName("android.app.servertransaction.LaunchActivityItem");
Field mActivityCallbacksField = ClientTransactionClz.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
Object mActivityCallbacksObj = mActivityCallbacksField.get(msg.obj);
List list = (List) mActivityCallbacksObj;
if (list.size() == 0) {
return false;
}
Object LaunchActivityItemObj = list.get(0);
if (!LaunchActivityItemClz.isInstance(LaunchActivityItemObj)) {
return false;
}
Field mIntentField = LaunchActivityItemClz.getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Intent mIntent = (Intent) mIntentField.get(LaunchActivityItemObj);
Intent realIntent = mIntent.getParcelableExtra("oldIntent");
if (realIntent != null) {
SharedPreferences sp = context.getSharedPreferences("name", MODE_PRIVATE);
boolean isLogin = sp.getBoolean("isLogin", false);
if (isLogin) {
mIntent.setComponent(realIntent.getComponent());
} else {
ComponentName componentName = new ComponentName(context, LoginActivity.class);
mIntent.putExtra("extraIntent", realIntent.getComponent().getClassName()); // 提供给登陆界面登陆成功后跳转到哪个目标页面
mIntent.setComponent(componentName);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false; // 返回 false 不影响系统的执行
}
}
private class AmsInvocationHandler implements InvocationHandler {
private final Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 系统使用 mInstance 的调用都会走到代理
if ("startActivity".contains(method.getName())) {
Intent intent = null;
int index = 0;
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof Intent) {
intent = (Intent) args[i];
index = i;
break;
}
}
if (intent != null) {
Intent proxyIntent = new Intent();
ComponentName componentName = new ComponentName(context, proxyActivity);
proxyIntent.setComponent(componentName);
proxyIntent.putExtra("oldIntent", intent);
args[index] = proxyIntent; // 替换真实意图
}
}
return method.invoke(iActivityManagerObject, args);
}
}
}
这样就能完成我们的效果了,写个 demo 测试下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Demo">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 没有注册 LoginActivity -->
<activity android:name=".Page1Activity" />
<activity android:name=".Page2Activity" />
</application>
</manifest>
public class MainActivity extends AppCompatActivity {
private Hooker hooker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hooker = new Hooker(this);
}
public void logout(View view) {
SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
sp.edit().putBoolean("isLogin", false).apply();
}
public void startPage1(View view) {
hooker.setProxyActivity(Page1Activity.class);
try {
hooker.hook();
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this, Page1Activity.class));
}
public void startPage2(View view) {
hooker.setProxyActivity(Page2Activity.class);
try {
hooker.hook();
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this, Page2Activity.class));
}
}
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
}
public void login(View view) throws ClassNotFoundException {
SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
sp.edit().putBoolean("isLogin", true).apply();
String className = getIntent().getStringExtra("extraIntent");
if (!TextUtils.isEmpty(className)) {
startActivity(new Intent(this, Class.forName(className)));
finish();
}
}
}