Activity 启动流程及其插件化

怎么讲

在开始这个主题之前,可能需要了解一些其它的知识,以便将这个问题讲明白,后面会以下面这个顺序开始。

  • Lancher 是怎么启动的
  • Launcher 做了什么
  • Activity 怎么使用及需要校验什么
  • Java动态代理
  • Activity 是如何启动的
  • 插件化是做什么
  • Activity 插件化

Android 启动

Launcher 启动

Android 系统启动的最后一步是启动一个 Home 应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个 Home 应用程序就是 Launcher

Launcher 有下面几个大版本:

  • Launcher.apk:android 2.1(Eclair) 版本以前。
  • Launcher2.apk:android 2.2(Froyo) 推出,支持 GPU 硬件 3D 加速。
  • Launcher3.apk:android 4.4(KitKat) 推出,大幅改版,桌面长按可呼出小工具,可配置,桌面个数无限。

SyetemServer 进程在启动的过程中会启动 ActivityManagerService,就是它将 Launcher 启动。

  1. SyetemServer 进程的 run 函数里面会初始化并启动 ActivityManagerService

    frameworks\base\services\java\com\android\server\SystemServer.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    private SystemServiceManager mSystemServiceManager;
    // TODO: remove all of these references by improving dependency resolution and boot phases
    private PowerManagerService mPowerManagerService;
    private ActivityManagerService mActivityManagerService;
    private DisplayManagerService mDisplayManagerService;
    private PackageManagerService mPackageManagerService;
    private PackageManager mPackageManager;
    private ContentResolver mContentResolver;
    public static void main(String[] args) {
    new SystemServer().run();
    }
    public SystemServer() {
    // Check for factory test mode.
    mFactoryTestMode = FactoryTest.getMode();
    }
    private void run() {
    ...
    ...
    // Create the system service manager.
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    // Start services.
    try {
    startBootstrapServices(); // 系统服务启动及初始化
    startCoreServices();
    startOtherServices(); // 启动 Home 程序 Launcher
    } catch (Throwable ex) {
    Slog.e("System", "******************************************");
    Slog.e("System", "************ Failure starting system services", ex);
    throw ex;
    }
    ...
    ...
    }
    private void startBootstrapServices() {
    ...
    ...
    // Activity manager runs the show.
    mActivityManagerService = mSystemServiceManager.startService(
    ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    // Power manager needs to be started early because other services need it.
    // Native daemons may be watching for it to be registered so it must be ready
    // to handle incoming binder calls immediately (including being able to verify
    // the permissions for those calls).
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    ...
    ...
    // The sensor service needs access to package manager service, app ops
    // service, and permissions service, therefore we start it after them.
    startSensorService();
    }
    private void startOtherServices() {
    ...
    ...
    mActivityManagerService.systemReady(new Runnable() {
    @Override
    public void run() {
    ...
    ...
    }
    });
    ...
    ...
    }
  2. ActivityManagerService 的 systemReady 函数内部

    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public void systemReady(final Runnable goingCallback) {
    ...
    // 最终会触发 startHomeActivityLocked 方法的调用
    ...
    }
    String mTopAction = Intent.ACTION_MAIN;
    Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
    intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
    }
    boolean startHomeActivityLocked(int userId, String reason) {
    ...
    ...
    Intent intent = getHomeIntent();
    ActivityInfo aInfo =
    resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
    intent.setComponent(new ComponentName(
    aInfo.applicationInfo.packageName, aInfo.name));
    ...
    ...
    if (app == null || app.instrumentationClass == null) {
    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
    mStackSupervisor.startHomeActivity(intent, aInfo, reason);
    }
    }
    return true;
    }
  3. 匹配规则启动 Launcher
    上面启动的应用程序有两个匹配规则:
    Action = Intent.ACTION_MAIN
    Category = Intent.CATEGORY_HOME

    packages\apps\Launcher3\AndroidManifest.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <activity
    android:name="com.android.launcher3.Launcher"
    android:launchMode="singleTask"
    android:clearTaskOnLaunch="true"
    android:stateNotNeeded="true"
    android:theme="@style/Theme"
    android:windowSoftInputMode="adjustPan"
    android:screenOrientation="nosensor"
    android:resumeWhilePausing="true"
    android:taskAffinity=""
    android:enabled="true">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.HOME" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.MONKEY"/>
    </intent-filter>
    </activity>

Launcher 干什么

Launcher在启动过程中会请求 PackageManagerService 返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序。

Launcher 模块中将加载系统 App 的逻辑放在了 LauncherModel 里面

packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
AllAppsList mBgAllAppsList;
private void loadAllApps() {
// Clear the list of apps
mBgAllAppsList.clear();
for (UserHandleCompat user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
if (DEBUG_LOADERS) {
Log.d(TAG, "getActivityList took "
+ (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
}
// Fail if we don't have any apps
// TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
return;
}
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfoCompat app = apps.get(i);
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));
}
final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
if (heuristic != null) {
runAfterBindCompletes(new Runnable() {
@Override
public void run() {
heuristic.processUserApps(apps);
}
});
}
}
// Post callback on main thread
mHandler.post(new Runnable() {
public void run() {
final long bindTime = SystemClock.uptimeMillis();
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(added);
if (DEBUG_LOADERS) {
Log.d(TAG, "bound " + added.size() + " apps in "
+ (SystemClock.uptimeMillis() - bindTime) + "ms");
}
} else {
Log.i(TAG, "not binding apps: no Launcher activity");
}
}
});
}

Activity 如何使用

  1. 常规配置如下

    1
    2
    3
    4
    5
    6
    7
    8
    <activity android:name=".MainActivity">
    <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    </activity>
    <activity android:name=".StubActivity"/>
  2. 启动

    1
    2
    3
    Intent intent = new Intent(MainActivity.this, StubActivity.class);
    startActivity(intent);
    startActivityForResult(intent, 0);

Java 动态代理

JDK 提供了动态代理方法,来让我们在插件化的时候很方便的实现各种代理功能。

Proxy.newProxyInstance

创建代理接口

1
2
3
4
5
6
7
8
9
import java.lang.reflect.Proxy;
/*
* 1. 类加载器(Class Loader)
* 2. 需要实现的接口数组
* 3. InvocationHandler接口。所有动态代理类的方法调用,都会交由 InvocationHandler 接口实现类里的 invoke() 方法去处理。这是动态代理的关键所在。
*/
Object newProxyInstance (ClassLoader loader,
Class[]<?> interfaces,
InvocationHandler h)

InvocationHandler

代理方法调用

1
2
3
4
5
6
7
8
9
import java.lang.reflect.InvocationHandler;
/*
* 1. 动态代理类的引用,通常情况下不需要它。但可以使用getClass()方法,得到proxy的Class类从而取得实例的类信息,如方法列表,annotation等。
* 2. 方法对象的引用,代表被动态代理类调用的方法。从中可得到方法名,参数类型,返回类型等等
* 3. args对象数组,代表被调用方法的参数。注意基本类型(int,long)会被装箱成对象类型(Interger, Long)
*/
Object invoke (Object proxy,
Method method,
Object[] args)

插件化做什么

一个简单的需求:宿主如何启动插件包中的服务或者UI

瓶颈

  1. 65536
  2. 功能模块的解耦和开发团队的分离是趋势,各个团队维护一个 App 的不同模块,那么就存在一个模块升级与 App 升级的问题

要做什么

  1. 代码加载
    类的加载可以使用 ClassLoader
    类加载器使用介绍
    还需要解决:

    • 生命周期管理
    • 类之间的依赖怎么处理
  2. 资源加载
    使用 AssetManager 的 addAssetPath 来加载,但资源加载最重要的一个问题便是宿主与插件之间的资源调用及冲突问题

  3. 终极目标

    • 宿主只负责 App 启动及插件服务的加载,不处理业务逻辑
    • 插件负责处理业务,通过服务器配置选择功能上线
    • 插件化开发过程是自由的
  4. 插件化手段
    插件化实际上是偷天换日,在插件化过程中我们找到那些相对不容易发生变化的变量。

    • 寻找 Hook 点
    • 寻找 静态变量/单例
    • 创建代理

Activity 的启动

继承关系

1
2
3
4
5
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.view.ContextThemeWrapper
↳ android.app.Activity

启动过程

流程图如下:

1. startActivity

frameworks\base\core\java\android\app\Activity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@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(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(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());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}

2. Instrumentation.execStartActivity

frameworks\base\core\java\android\app\Instrumentation.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
// 检测 AMS 校验返回的结果
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
public 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");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:
// Fail silently for this case so we don't break current apps.
// TODO(b/22929608): Instead of failing silently or throwing an exception,
// we should properly position the activity in the stack (i.e. behind all current
// user activity/task) and not change the positioning of stacks.
Log.e(TAG,
"Not allowed to start background user activity that shouldn't be displayed"
+ " for all users. Failing silently...");
break;
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}

3. ActivityManagerNative.getDefault().startActivity

目前为止,所有操作实际是在当前应用进程中完成。
ActivityManagerNative getDefault() 返回的是一个 IActivityManager 它是一个 IBinder 对象,Android 中的跨进程通讯基本都是使用它。
getDefault 里面会通过 Binder 机制获取 AMS 系统服务

core\java\android\app\ActivityManagerNative.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};

从它的名字可以看出来,它是 ActivityManagerService 在应用 APP 本地(Native)的通讯代理,Actvity 与 ActivityManagerService(AMS) 的所有通讯都是通过它。

core\java\android\app\IActivityManager.java

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* System private API for talking with the activity manager service. This
* provides calls from the application back to the activity manager.
*
* {@hide}
*/
public interface IActivityManager extends IInterface {
...
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
...
}

4. ActivityManagerService.startActivity

services\core\java\com\android\server\am\ActivityManagerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, options,
UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, options, false, userId, null, null);
}

5. ActivityStackSupervisor.startActivityMayWait

Activity 的生命周期及栈管理都是通过 ActivityStack 来完成,而 ActivityStackSupervisor 刚负责统筹所有的 ActvityStack 管理

  • mHomeStack:Launcher 管理
  • mFocusedStack:当前活动
  • mLastFocusedStack:上一次活动

services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/** The stack containing the launcher app. Assumed to always be attached to
* Display.DEFAULT_DISPLAY. */
private ActivityStack mHomeStack;
/** The stack currently receiving input or launching the next activity. */
private ActivityStack mFocusedStack;
/** If this is the same as mFocusedStack then the activity on the top of the focused stack has
* been resumed. If stacks are changing position this will hold the old stack until the new
* stack becomes resumed after which it will be set to mFocusedStack. */
private ActivityStack mLastFocusedStack;
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
Bundle options, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
...
// intent 参数处理
...
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
componentSpecified, null, container, inTask);
...
}
final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
ActivityContainer container, TaskRecord inTask) {
...
...
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = ActivityManager.START_CLASS_NOT_FOUND;
}
...
...
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);
}

如果启动的 Activity 在 AndroidManifest.xml 中没有注册,上面这里会有一个 ActivityManager.START_CLASS_NOT_FOUND 错误码判断返回,返回后可以在应用进程 App 端执行校验 checkStartActivityResult

6. ActivityStackSupervisor.realStartActivityLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), 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);
}
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
...
...
app.forceProcessStateUpTo(mService.mTopProcessState);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
...
...
}

7. ProcessRecord.thread

这个类保存了所有正在运行的 java 进程信息。

services\core\java\com\android\server\am\ProcessRecord.java

1
2
3
final class ProcessRecord {
IApplicationThread thread;
}

app.thread 实际上是一个 IApplicationThread 对象

core\java\android\app\IApplicationThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface IApplicationThread extends IInterface {
...
void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving,
int configChanges, boolean dontReport) throws RemoteException;
void scheduleStopActivity(IBinder token, boolean showWindow,
int configChanges) throws RemoteException;
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;
}

这里 IApplicationThread 实际也是一个 IBinder 对象,从名字可以看出,它是 AMS 与 App 所在进程通讯的桥梁。

8. ApplicationThreadNative

这个里面有一个 ApplicationThreadProxy,它就是与 AMS 通讯的代理

core\java\android\app\ApplicationThreadNative.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class ApplicationThreadProxy implements IApplicationThread {
private final IBinder mRemote;
public ApplicationThreadProxy(IBinder remote) {
mRemote = remote;
}
public final IBinder asBinder() {
return mRemote;
}
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
intent.writeToParcel(data, 0);
data.writeStrongBinder(token);
data.writeInt(ident);
info.writeToParcel(data, 0);
curConfig.writeToParcel(data, 0);
if (overrideConfig != null) {
data.writeInt(1);
overrideConfig.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
compatInfo.writeToParcel(data, 0);
data.writeString(referrer);
data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
data.writePersistableBundle(persistentState);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
data.writeInt(isForward ? 1 : 0);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
}

然后,ApplicationThreadNative 会有一个对 ApplicationThreadProxy 的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
static public IApplicationThread asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IApplicationThread in =
(IApplicationThread)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ApplicationThreadProxy(obj);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
...
switch (code) {
case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
Intent intent = Intent.CREATOR.createFromParcel(data);
IBinder b = data.readStrongBinder();
int ident = data.readInt();
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
Configuration overrideConfig = null;
if (data.readInt() != 0) {
overrideConfig = Configuration.CREATOR.createFromParcel(data);
}
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
String referrer = data.readString();
IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
PersistableBundle persistentState = data.readPersistableBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
boolean notResumed = data.readInt() != 0;
boolean isForward = data.readInt() != 0;
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
referrer, voiceInteractor, procState, state, persistentState, ri, pi,
notResumed, isForward, profilerInfo);
return true;
}
}
...
}
}

9. ActivityThread.ApplicationThread.scheduleLaunchActivity

这里会通过 mH 这个 Handler,完成消息到主线程的转发

core\java\android\app\ActivityThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// ActivityThread 成员变量 mAppThread 的方法调用
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
// 最终调用到此时 完成消息 到 主线程的转发
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
// ActivityThread 成员变量 mH 的方法调用
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent);
...
}

10. performLaunchActivity

Activity被真实的创建

core\java\android\app\ActivityThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 真正创建 Activity 的地方
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
// 使用 ClassLoader new Activity
java.lang.ClassLoader cl = r.packageInfo.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);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
// 创建 Application (如果还没有创建成功的话),后面就调用回调
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
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);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}

Activity 插件化

上面流程是完整的 Activity 启动流程,简单一点逻辑如下:

由于 SystemServer 是系统进程,我们无法处理,所以需要在第一步及最后一步作插件化准备。

目的

启动一个在没有在 AndroidManifest.xml 中注册的 Activity。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 替身 Activity, 用来欺骗 AMS -->
<activity android:name=".ProxyActivity"/>
<!--
<activity android:name=".TargetActivity" />
-->
</application>

我们要实现下面的代码启动 TargetActivity,因为 TargetActivity没有在xml中配置,所以这里应该会报错

1
startActivity(new Intent(MainActivity.this, TargetActivity.class));

使用 ProxyActivity 欺骗 AMS

由于 Activity 的调用逻辑很复杂,在进入 AMS 调用之间,我们 hook 的时机越早,出现问题的可能性越大,因为后续的调用越容易出问题。
App 进程在进入 SystemServer 进程的最后一步是在 ActivityManagerNative.getDefault()

这是一个静态变量,同时是单例
我们需要 hook 掉 IActivityManager.startActivity 方法,在里面把 TargetActivity 换成 ProxyActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
// 需要 hook 的方法
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;

这里要使用动态代理:

  1. 选择 hook 的方法 startActivity

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    class IActivityManagerHandler implements InvocationHandler {
    private static final String TAG = "IActivityManagerHandler";
    // 定义一个代理对象
    Object mProxy;
    // 保存真身
    public IActivityManagerHandler(Object body) {
    mProxy = body;
    }
    // 选择需要代理重写的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("startActivity".equals(method.getName())) {
    Intent realIntent;
    int index = 0;
    // 找到 Intent 参数
    for (int i = 0; i < args.length; i++) {
    if (args[i] instanceof Intent) {
    index = i;
    break;
    }
    }
    realIntent = (Intent) args[index];
    // 创建新的 Intent
    Intent newIntent = new Intent();
    // ProxyActivity 的包名
    String stubPackage = "com.test.hook.app";
    // 这里我们把启动的 Activity临时替换为 ProxyActivity
    ComponentName componentName = new ComponentName(stubPackage, ProxyActivity.class.getName());
    newIntent.setComponent(componentName);
    // 把我们原始要启动的 TargetActivity 先存起来
    newIntent.putExtra("REAL_INTENT", realIntent);
    // 替换掉Intent, 达到欺骗AMS的目的
    args[index] = newIntent;
    Log.d(TAG, "hook success");
    // hook
    return method.invoke(mProxy, args);
    }
    // 这里我们只处理 startActivity 方法,其它方法不动
    return method.invoke(mProxy, args);
    }
    }
  2. 替换代理对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public static void hookActivityManagerNative() throws ClassNotFoundException,
    NoSuchMethodException, InvocationTargetException,
    IllegalAccessException, NoSuchFieldException {
    Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
    Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
    gDefaultField.setAccessible(true);
    Object gDefault = gDefaultField.get(null);
    // gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
    Class<?> singleton = Class.forName("android.util.Singleton");
    Field mInstanceField = singleton.getDeclaredField("mInstance");
    mInstanceField.setAccessible(true);
    // ActivityManagerNative 的 gDefault对象里面原始的 IActivityManager对象
    Object realIActivityManager = mInstanceField.get(gDefault);
    // 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
    Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
    Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
    new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(realIActivityManager));
    mInstanceField.set(gDefault, proxy);
    }

ProxyActivity -> TargetActivity

由于之前替换了 TargetActivity,所以需要在合适的时候换回来。
只有在 AMS 校验逻辑完成以后,流程进入 App 进程之后,这里可以选择 ActivityThread(静态变量) 的 Handler mH,它是一个 final 对象,根据 Handler 的工作原理,我只可以 hook 掉它的 Callback,我们自定义一个 Callback 处理自己的逻辑。

  1. 选择 hook 的方法 Callback

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    class ActivityThreadHandlerCallback implements Handler.Callback {
    Handler mProxy;
    public ActivityThreadHandlerCallback(Handler body) {
    mProxy = body;
    }
    @Override
    public boolean handleMessage(Message msg) {
    switch (msg.what) {
    // 只处理这个消息
    // ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100
    case 100:
    handleLaunchActivity(msg);
    break;
    }
    mProxy.handleMessage(msg);
    return true;
    }
    private void handleLaunchActivity(Message msg) {
    // 这里简单起见,直接取出TargetActivity;
    Object obj = msg.obj;
    try {
    // 把替身恢复成真身
    Field intent = obj.getClass().getDeclaredField("intent");
    intent.setAccessible(true);
    Intent realIntent = (Intent) intent.get(obj);
    // 获取之前保存的intent对象
    Intent target = realIntent.getParcelableExtra("REAL_INTENT");
    realIntent.setComponent(target.getComponent());
    } catch (NoSuchFieldException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    }
  2. 替换代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public static void hookActivityThreadHandler() throws Exception {
    // 先获取到当前的 ActivityThread 对象
    Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
    Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
    currentActivityThreadField.setAccessible(true);
    Object currentActivityThread = currentActivityThreadField.get(null);
    // 由于 ActivityThread一个进程只有一个,我们获取这个对象的 mH
    Field mHField = activityThreadClass.getDeclaredField("mH");
    mHField.setAccessible(true);
    Handler mH = (Handler) mHField.get(currentActivityThread);
    // 获取 mCallback 字段
    Field mCallBackField = Handler.class.getDeclaredField("mCallback");
    mCallBackField.setAccessible(true);
    mCallBackField.set(mH, new ActivityThreadHandlerCallback(mH));
    }

最终调用

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
try {
HookHelper.hookActivityManagerNative();
HookHelper.hookActivityThreadHandler();
} catch (Throwable throwable) {
throw new RuntimeException("hook failed", throwable);
}
}

以上只是借鉴于 Activity 的启动方式,顺便梳理一下如何使用 java 动态代理来完成 Activity 的简单插件化, 之所以说简单,是因为这里还有很多问题没有解决,最重要的是 插件包 与 宿主的分离 以及 ClassLoader 的加载,后面会作一个专题另外讲解。

引用

KeyPoint 博文收录
类加载说明
Android 应用启动时序图