1. 前言
在Android插件化开发指南——Hook技术(一)【长文】对AMS进行Hook的时候,我重新创建了一个低版本的项目,并创建了对应的模拟器来运行程序,以得到AMS对象。当时所使用的API版本为30,所以其实可以知道25其实和30的AMS的Hook会略有不同。实际上两个分水岭为23和26。前面几篇博客中所给出的Hook得到AMS对象的为23到26之间的版本。对于大于等于26的版本需要重新做适配。
再次查看Android版本和API级别的对应关系:代号、标记和细分版本号 我们知道从Oreo即Android版本为8.0.0开始,API 级别就为 26。且http://androidxref.com/也支持查看对应的高版本系统的源码,所以这里就尝试以源码网站中的Oreo - 8.1.0_r33为例开始。
2. API版本大于26后的AMS
对于前面的流程从startActivity->startActivityForResult->Instrumentation->ams.startActivity的这个流程这里不再继续看源码进行追踪。这里直接找到Instrumentation这个类,对应的execStartActivity方法。简略版如下:
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 = ActivityManager.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;
}
不妨将之前博客中写的API 25版本也放置在这里:
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 = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
很明显这里得到AMS对象不再是使用ActivityManagerNative.getDefault(),而是ActivityManager.getService()方法。所以这里需要继续追踪一下ActivityManager这个类,ActivityManager.java。
public static IActivityManager getService(){
return IActivityManagerSingleton.get();
}
这里按照语义还是使用了一个单例对象来进行存储,接着继续看这个单例对象IActivityManagerSingleton的源码。
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
portected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
对于这个单例属性只需要执行它的create方法就可以创建对应的AMS。所以我们需要得到这个单例对象。类似的,由于其包装在Singleton类中,所以还是需要继续查看Singleton的源码:
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;
}
}
}
这个类和前面的没有什么区别。所以这里还是首先得到这个单例类对象,然后通过create方法来获取到AMS对象。即:
Object iActivityManagerSingletonValue = null;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
Field iActivityManagerSingletonField = ActivityManager.class.getDeclaredField("IActivityManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
iActivityManagerSingletonValue = iActivityManagerSingletonField.get(null);
}else{
Class<?> aClass = Class.forName("android.app.ActivityManagerNative");
Field getDefault = aClass.getDeclaredField("gDefault");
getDefault.setAccessible(true);
iActivityManagerSingletonValue = getDefault.get(null);
}
Class<?> singletonClazz = Class.forName("android.util.Singleton");
Field mInstance = singletonClazz.getDeclaredField("mInstance");
mInstance.setAccessible(true);
Object amsObj = mInstance.get(iActivityManagerSingletonValue);
3. API版本大于28后的ActivityThread
需要注意的是在API版本大于28后,ActivityThread中对消息的处理也不一样。注意到API级别28对应的Android版本为9。刚好在http://androidxref.com/中提供了Pie - 9.0.0_r3系统的源码。但是这个网站用来查看代码实在是太卡了,所以这里还是修改grdle文件,然后直接在本地查看:
android {
compileSdkVersion 28
buildToolsVersion "28.0.6"
defaultConfig {
applicationId "com.weizu.myapplication"
minSdkVersion 28
targetSdkVersion 28
versionCode 1
versionName "1.0"
...
在我本地其实是下载了对应的SDK,如下图:  如果需要下载对应版本的SDK,直接打开Seetings->Android SDK然后选择下载即可。这里我选择28。
找到ActivityThread的消息处理对象mH,可以发现消息标识的编码已经没有了之前的100,也就是没有了LAUNCH_ACTIVITY。这里对应的修改为了EXECUTE_TRANSACTION至于怎么来的,这里就不追踪源码了。现在的为:
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
transaction.recycle();
}
break;
之前的为:
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, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
且在之前的代码中我们做Hanlder.Callback的时候,反射的是ActivityClientRecord这个对象,然后从r对象中得到其属性intent,然后将这个intent进行替换。
这里类似的首先需要追踪一下TransactionExecutor这个类,然后看下execute这个方法会执行什么?
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
log("End resolving transaction");
}
继续查看executeCallbacks方法,但是在这个方法也没有找到和Intent相关的东西。
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null) {
return;
}
...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
...
但是在executeCallbacks中进行了List<ClientTransactionItem> callbacks的一个遍历。所以可以看看ClientTransactionItem中存放的什么内容。很遗憾只是一个抽闲的类,没有具体的实现。所以我们可通过ClientTransaction,找找addCallback方法。
public void addCallback(ClientTransactionItem activityCallback) {
if (mActivityCallbacks == null) {
mActivityCallbacks = new ArrayList<>();
}
mActivityCallbacks.add(activityCallback);
}
所以我们只要找到调用addCallback的地方就可以知道ClientTransactionItem中存放的是什么东西。很不幸不太了解AMS的启动,所以这里还是直接给出答案:ActivityStackSupervisor。
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
对应的LaunchActivityItem的类中就有一个mIntent属性:
public class LaunchActivityItem extends ClientTransactionItem {
private Intent mIntent;
...
}
所以流程为:
- 获取到
mActivityCallbacks 集合; - 遍历
mActivityCallbacks ,得到LaunchActivityItem - 替换
LaunchActivityItem 中的Intent
因为mActivityCallbacks 属于ClientTransaction,首先是拿到ClientTransaction 实例对象。在ActivityThread的case EXECUTE_TRANSACTION:处理中给了从消息中得到ClientTransaction对象的方法,即:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
最终的代码如下:
private void handleLaunchActivity28(Message message) {
try {
Object clientTransactionObj = message.obj;
Field mActivityCallbacksField = clientTransactionObj.getClass().getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List mActivityCallbacksValue = (List) mActivityCallbacksField.get(clientTransactionObj);
for (Object o : mActivityCallbacksValue) {
if(o.getClass().getName().equals("android.app.servertransaction.LaunchActivityItem")){
Field mIntentField = o.getClass().getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Intent newIntent = (Intent) mIntentField.get(o);
Intent oldIntent = newIntent.getParcelableExtra(ORIGIN_INTENT);
if(oldIntent != null){
mIntentField.set(o, oldIntent);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
 最后测试效果也成功进入到了插件的Activity。
代码地址:https://github.com/baiyazi/pluginLearn/tree/main/demo2
References
|