在上一节,我们主要介绍了如果通过反射来加载插件中的类,调用类中的方法;既然插件是一个apk,其实最重要的是启动插件中的Activity、Service等组件,因为像Activity这些组件,需要在清单文件中注册,否则启动的时候会报下面的错误
android.content.ActivityNotFoundException:
Unable to find explicit activity class {com.lay.image_process/com.lay.image_process.MainActivity2};
have you declared this activity in your AndroidManifest.xml?
那么如果要启动插件中的Activity,就需要将其注册到宿主app的清单文件中
其实想要启动插件中的四大组件,例如Activity,就需要熟悉Activity的启动流程,为什么在没有注册的情况下,不能启动
开头我们提到,为什么没有注册过的Activity不能启动?是因为当系统启动一个Activity的时候,需要通过AMS检测,当前被启动的Activity是否被注册,如果没有注册,那么就会报错,所以我们需要采用Hook的方式来欺骗系统已达到我们的目的。
在应用层,我们能看到的就是,宿主app启动了插件中的Activity,其实在内部做了很多处理:\
(1)首先将插件中的Activity替换成宿主中已经注册过的ProxyActivity,在启动的时候,通过AMS检测发现当前启动的Activity已经被注册过了,那么就会继续往下执行; (2)当AMS检测完成之后,再将宿主中的ProxyActivity替换成插件中的Activity,最终启动的就是插件中的Activity。
//实际启动代码<br></br>
val intent = Intent()
intent.component = ComponentName("com.lay.plugin","com.lay.plugin.MainActivity")
startActivity(intent)
我们看到启动方式很简单,但是内部其实做了很多的Hook处理,如果想知道怎么用,那么就跟着这个思路一起走下去。
对于Activity的启动流程,我想大家都非常了解了,记住关键的几个类Instrument、ActivityManagerService、ApplicationThread......,下面简单介绍下流程。
当调用Instrument的execStartActivity方法时,通过ActivityTaskManager.getService()获取AMS服务,调用AMS的startActivity方法,并返回检测的结果。
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);
}
// ......
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
//这里就是通过ActivityTaskManager获取AMS服务,调用AMS的startActivity方法,并返回结果
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), 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;
}
我们看一下checkStartActivityResult方法究竟做了什么?我们看一下START_CLASS_NOT_FOUND这个结果,最终抛出的错误是不是就是文章开头的错误
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
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_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start voice activity on a hidden session");
case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startAssistantActivity does not match active session");
case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start assistant activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for "
+ intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
也就是说在这个位置就已经检测完成,当前启动的Activity是否在清单文件中注册,也就是说,Hook点要在这个检测方法之前,完成对插件Activity的替换,这是Hook点1.
我们接着往下看AMS里主要做了啥
public class ActivityTaskManagerService extends IActivityTaskManager.Stub
ActivityTaskManagerService继承自IActivityTaskManager.Stub接口,作为一个服务端的角色,接受客户端的请求,例如启动Activity,AMS除了做Intent启动的Activity检测之外,还做了什么事呢?
在ATMS中调用startActivity方法,最终是调用了startActivityAsUser方法,这个方法中,首先检查了调用者的权限,然后调用了ActivityStartController一系列方法,用于启动前的任务栈处理
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
//检查调用者的权限
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
再深入的源码,大家可以自己去查看,最终AMS会判断启动这个Activity的进程是否启动,没有启动的话就启动app进程,如果已经启动了会调用realStartActivityLocked方法
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, 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.
knownToBeDead = true;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
在realStartActivityLocked方法中,首先会创建一个启动Activity的Transaction,会通过ApplicationThread回调给客户端启动Activity,在AMS和客户端通信时,有两个对象需要注意:ActivityThread和ApplicationThread,ApplicationThread其实是ActivityThead在AMS的代理对象,AMS通过调用ApplicationThread与ActivityThead建立通信
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
// The LaunchActivityItem also contains process configuration, so the configuration change
// from WindowProcessController#setProcess can be deferred. The major reason is that if
// the activity has FixedRotationAdjustments, it needs to be applied with configuration.
// In general, this reduces a binder transaction if process configuration is changed.
//......
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final boolean isTransitionForward = r.isTransitionForward();
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
r.getLaunchedFromBubble()));
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}
所以AMS这里的作用就是:检测Activity合法性、检测app进程是否启动、通过ApplicationThead与ActivityThead建立通信。
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
我们看下服务端的代理对象ApplicationThread,主要是处理AMS端的请求,例如realStartActivityLocked方法中创建的启动Activity的ClientTransaction,接收到之后,交给了ActivityThread处理。
首先我们看下ActivityThread是什么,我们看到它是继承自ClientTransactionHandler,也就是说,在App进程内的处理,都是通过Handler来发送消息
public final class ActivityThread extends ClientTransactionHandler
public abstract class ClientTransactionHandler {
// Schedule phase related logic and handlers.
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
}
对于EXECUTE_TRANSACTION消息类型,就是用来处理AMS端发送来的消息
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
最终是调用了TransactionExecutor的execute方法,在execute方法中,调用executeCallbacks方法,我们可以在realStartActivityLocked方法中看到,在transaction添加了callback,所以这个方法就是执行这些callback
public void execute(ClientTransaction transaction) {
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
executeCallbacks方法比较简单,就是遍历获取所有的callback,然后调用callback的execute方法,也就是LaunchActivityItem的execute方法
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null || callbacks.isEmpty()) {
// No callbacks to execute, return early.
return;
}
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
final int postExecutionState = item.getPostExecutionState();
final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
item.getPostExecutionState());
if (closestPreExecutionState != UNDEFINED) {
cycleToPath(r, closestPreExecutionState, transaction);
}
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
if (r == null) {
// Launch activity request will create an activity record.
r = mTransactionHandler.getActivityClient(token);
}
if (postExecutionState != UNDEFINED && r != null) {
// Skip the very last transition and perform it by explicit state request instead.
final boolean shouldExcludeLastTransition =
i == lastCallbackRequestingState && finalState == postExecutionState;
cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
}
}
}
在LaunchActivityItem的execute方法中,执行了ClientTransactionHandler的handleLaunchActivity方法,也就是ActivityThread的handleLaunchActivity方法,这里才是真正要启动这个Activity。
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = client.getLaunchingActivity(token);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
在performLaunchActivity方法中,通过Instrument类来创建新的Activity,并执行Activity的onCreate、onStart、onResume方法等,Activity就算是正式启动,所以第二个Hook点,我们知道了吗?
因为在performLaunchActivity方法调用之前,Activity都不算是真正地启动,也就是说,将宿主中的ProxyActivity替换成插件的Activity就需要在performLaunchActivity方法之前
通过上面的源码,我们知道了AMS在什么时机去检测Activity合法性,以及Activity什么时候真正地启动,所以我们分步骤,先处理AMS合法性校验问题。
首先我们先看一下,如何通过Hook的方式,欺骗AMS过Activity合法性检测这一关,因为从前面的源码我们知道,调用startActivity最终会在Instrument的execStartActivity方法中检测,就是下面这两行代码
// 位置①
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
首先我们先看一下ActivityTaskManager.getService()最终返回的是一个IActivityTaskManager代理对象,是从IActivityTaskManagerSingleton中取出来的;
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
所以想要代替系ActivityTaskManager.getService()的返回值,首先反射获取IActivityTaskManagerSingleton这个属性
val clazz4ATM = Class.forName("android.app.ActivityTaskManager")
val filed = clazz4ATM.getDeclaredField("IActivityTaskManagerSingleton")
filed.isAccessible = true
//获取ActivityTaskManager中IActivityTaskManagerSingleton属性的值
val IActivityTaskManagerSingletonField = filed.get(null)
我们看到,IActivityTaskManagerSingleton其实是一个单例,需要通过get方法才能获取真正的实例,那么我们先看下Singleton是啥
public abstract class Singleton<T> {
@UnsupportedAppUsage
public Singleton() {
}
@UnsupportedAppUsage
private T mInstance;
protected abstract T create();
@UnsupportedAppUsage
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
其实还是比较简单的一个单例类,通过get方法拿到的其实就是mInstance,也就是说getService()拿到的就是这个mInstance,只不过是对IActivityTaskManager做了一层封装。
//从Singleton中获取对象
val singletonClazz = Class.forName("android.util.Singleton")
val mInstance = singletonClazz.getDeclaredField("mInstance")
mInstance.isAccessible = true
val taskManagerInstance = mInstance.get(IActivityTaskManagerSingletonField)
那么之前通过反射,拿到了Singleton对象,那么现在通过反射获取mInstance属性就拿到了getService()的返回值。
既然我们要hook系统的执行方式,当我们调用startActivity的时候,系统流程一步一步执行到位置①,这个时候,我们把getService()的返回值替换,换成我们自己处理过的IActivityTaskManager,从而
因为我们想要替换getService()的返回值,而且返回值是一个IActivityTaskManager接口对象,其实第一时间就会想到动态代理,那么动态代理是什么原理呢?
interface proxyInterface{
fun execute()
}
例如有一个接口,如果我们想要执行execute方法,那么就需要实现一个具体类,然后调用execute方法,这样其实在程序运行之前,就已经知道执行者是谁了;而动态代理则是程序在运行时,动态生成一个对象,这个时候才能知道执行者是谁,例如:
val instance = Proxy.newProxyInstance(classLoader, arrayOf(proxyInterface::class.java),object : InvocationHandler{
override fun invoke(
proxy: Any?,
method: java.lang.reflect.Method?,
args: Array<out Any>?
): Any {
//
Log.e("TAG","执行execute方法之前")
return method?.invoke(proxy,args)!!
}
})
(instance as proxyInterface).execute()
通过Proxy调用newProxyInstance方法,传入的参数为类加载器、接口的class对象,需要实现一个接口InvocationHandler,其中method为调用者调用的某个方法,这个方法调用之前,可以插入一些逻辑判断,更为灵活;
这样就意味着,我们可以创建一个IActivityTaskManager的动态代理对象,替换系统的getService()返回的IActivityTaskManager对象,那么在动态代理对象调用startActivity之前,可以对入参做处理。
val proxyClazz = Class.forName("android.app.IActivityTaskManager")
val newTaskManagerInstance = Proxy.newProxyInstance(Thread.currentThread().contextClassLoader, arrayOf(proxyClazz),object : InvocationHandler{
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
//做相应参数的处理
return method?.invoke(taskManagerInstance,args)!!
}
})
//替换
mInstance.set(singletonClazz,newTaskManagerInstance)
因为IActivityTaskManager中的方法非常多,因此需要根据方法名去过滤,只能对startActivity方法进行处理,当startActivity执行时,首先会将Intent类型参数取出来,把Intent替换成宿主中的ProxyActivity,但是真实的Intent不能丢掉,等合适的时间会重置回来,因此可以保存在代理的Intent中
method?.let {
if (it.name == "startActivity") {
//修改Intent的值
args?.let { args ->
var targetIndex = 0
for (index in args.indices) {
if (args[index] is Intent) {
targetIndex = index
break
}
}
val oldIntent = args[targetIndex] as Intent
val intentProxy = Intent()
intentProxy.component = ComponentName(
"com.lay.image_process",
"com.lay.image_process.ProxyActivity"
)
intentProxy.putExtra("old_intent", oldIntent)
args[targetIndex] = intentProxy
}
}
}
这个时候,当我们启动插件中的Activity时,启动的就是这个代理Activity;这里需要说明一点就是,因为源码是Java写的,所以我们在Hook时,尽量还是用跟源码一致的语言,否则可能会出现类型不匹配的问题,详细源码见附录1
通过前面的源码,我们知道在AMS的realStartActivityLocked方法中(辛苦伙伴们自己爬楼),是创建了一个ClientTransaction对象,然后在ClientTransaction对象中添加了callback,在启动Activity的时候,添加的callback对象为LaunchActivityItem,我们看下LaunchActivityItem源码
public class LaunchActivityItem extends ClientTransactionItem {
@UnsupportedAppUsage
private Intent mIntent;
private int mIdent;
@UnsupportedAppUsage
private ActivityInfo mInfo;
其他的先不用看,第一个参数就是mIntent,这个mIntent其实就是在之前AMS中替换的Intent,现在的目标就是将其替换成插件中的Activity。
那么在哪拿到这个对象呢?我们继续爬楼,在之前提到ActivityThread其实是一个Handler,通过Message的tag来分别处理数据。
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
当启动Activity的时候,AMS通过ApplicationThread代理发送的消息类型为EXECUTE_TRANSACTION,也就是说,我们可以Hook系统的Handler,当接收到EXECUTE_TRANSACTION消息时,把Intent给替换掉。
在Activity中有一个Handler类H,这个类就负责接收Message然后处理
class H extends Handler{
public static final int EXECUTE_TRANSACTION = 159;
}
我们可以看到,在ActivityThread中是直接new出来,我们知道,当调用Handler的send方法时,在底层是调用了dispatchMessage方法从消息池中取出数据分发
@UnsupportedAppUsage
final H mH = new H();
因为空参构造方法,mCallback是空的,所以会直接走handleMessage方法,所以我们如果想拿消息自己去处理,那么可以自己创建一个mCallback对象赋值给mH的callback,那么是不就能走我们自己的逻辑处理了呢
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
首先我们先把前面梳理的思路通过反射梳理出来,有几个属性先强调一下,一个是sCurrentActivityThread,这个是ActivityThread类中的一个属性,就是当前对象,通过获取这个属性的值,来获取ActivityThread中的非静态属性值;还有一个就是Handler中的mCallback,因为系统Handler创建时没有设置callback,所以我们自己创建了一个callback,并给它赋值
public static void hookHandler() {
try {
Class<?> activityThreadClazz = Class.forName("android.app.ActivityThread");
//获取到ActivityThread对象
Field sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);
//获取mH属性
Field mHField = activityThreadClazz.getDeclaredField("mH");
mHField.setAccessible(true);
//获取mH Handler对象
Object mH = mHField.get(sCurrentActivityThread);
//反射Handler
Class<?> handlerClazz = Class.forName("android.os.Handler");
Field mCallbackField = handlerClazz.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
//创建callback对象
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
//处理Intent替换的逻辑
doIntentReplace(msg)
return false;
}
};
//给系统Handler赋值
mCallbackField.set(mH, callback);
} catch (Exception exception) {
}
}
好了,那么下面的逻辑,主要就是给Intent替换。我们主要关心EXECUTE_TRANSACTION这个tag的处理。
public class ClientTransaction implements Parcelable, ObjectPoolItem {
/** A list of individual callbacks to a client. */
@UnsupportedAppUsage
private List<ClientTransactionItem> mActivityCallbacks;
/**
* Add a message to the end of the sequence of callbacks.
* @param activityCallback A single message that can contain a lifecycle request/callback.
*/
public void addCallback(ClientTransactionItem activityCallback) {
if (mActivityCallbacks == null) {
mActivityCallbacks = new ArrayList<>();
}
mActivityCallbacks.add(activityCallback);
}
}
当我们获取到Message携带的对象,其实就是ClientTransaction,我们看下源码,当调用addCallback的时候,就是将ClientTransactionItem放在了mActivityCallbacks中,所以拿到mActivityCallbacks就能拿到我们想要的LaunchActivityItem
private static void doIntentReplace(Message msg) {
switch (msg.what) {
case 159:
//获取
Class<?> transactionClazz = msg.obj.getClass();
try {
Field mActivityCallbacksField = transactionClazz.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List callbacks = (List) mActivityCallbacksField.get(msg.obj);
for (int i = 0; i < callbacks.size(); i++) {
Object transactionItem = callbacks.get(i);
//判断是不是LaunchActivityItem
if (transactionItem.getClass().getName().equals("android.app.servertransaction.LaunchActivityItem")) {
//获取mIntent属性
Field mIntentField = transactionItem.getClass().getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Log.e("TAG", "intent " + mIntentField.get(transactionItem));
Intent mIntent = (Intent) mIntentField.get(transactionItem);
Intent oldIntent = mIntent.getParcelableExtra("old_intent");
mIntentField.set(transactionItem, oldIntent);
// mIntent.setComponent(oldIntent.getComponent()); 这种方式同样有效
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
这样我们拿到了LaunchActivityItem中的mIntent之后,这个其实是代理的Intent,需要从中取出我们之前在HookAMS的时候保存的真正的Intent,并赋值,这个时候,Activity启动的时候启动的就是插件中的Activity。
其实,我们在学习插件化的时候,其实知识点还是很多的,像:Android类加载机制、Activity的启动流程、Hook原理等,并且能够深入源码,这一块其实是面试的重点和难点;这一节我们已经启动了插件中的Activity,其实像Service、BroadcastReceiver等组件,原理是一致,像Activity已经启动了,但是资源文件并没有被加载,所以下一节将着重介绍如何加载插件中的资源。
public static void HookAMS() {
try {
Class<?> atmClazz = Class.forName("android.app.ActivityTaskManager");
Field iActivityTaskManagerSingletonField = atmClazz.getDeclaredField("IActivityTaskManagerSingleton");
iActivityTaskManagerSingletonField.setAccessible(true);
Object atmSingleton = iActivityTaskManagerSingletonField.get(null);
Class<?> singletonClazz = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
final Object atmService = mInstanceField.get(atmSingleton);
Class<?> proxyClazz = Class.forName("android.app.IActivityTaskManager");
Object newProxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{proxyClazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("startActivity")) {
int targetIndex = 0;
//修改Intent的值
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
targetIndex = i;
break;
}
}
Intent oldIntent = (Intent) args[targetIndex];
Intent proxyIntent = new Intent();
proxyIntent.setComponent(new ComponentName("com.lay.image_process", "com.lay.image_process.MainActivity2"));
proxyIntent.putExtra("old_intent", oldIntent);
args[targetIndex] = proxyIntent;
}
Log.e("TAG", "atmService=" + atmService + " method=" + method + ", args=" + args);
return method.invoke(atmService, args);
}
});
mInstanceField.set(atmSingleton, newProxyInstance);
} catch (Exception e) {
Log.e("TAG", "e--" + e.getMessage());
e.printStackTrace();
}
}
public static void hookHandler() {
try {
Class<?> activityThreadClazz = Class.forName("android.app.ActivityThread");
//获取到ActivityThread对象
Field sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);
//获取mH属性
Field mHField = activityThreadClazz.getDeclaredField("mH");
mHField.setAccessible(true);
//获取mH Handler对象
Object mH = mHField.get(sCurrentActivityThread);
//反射Handler
Class<?> handlerClazz = Class.forName("android.os.Handler");
Field mCallbackField = handlerClazz.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
//创建callback对象
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
//处理Intent替换的逻辑
doIntentReplace(msg);
return false;
}
};
//给系统Handler赋值
mCallbackField.set(mH, callback);
} catch (Exception exception) {
}
}
private static void doIntentReplace(Message msg) {
switch (msg.what) {
case 159:
//获取
Class<?> transactionClazz = msg.obj.getClass();
try {
Field mActivityCallbacksField = transactionClazz.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List callbacks = (List) mActivityCallbacksField.get(msg.obj);
for (int i = 0; i < callbacks.size(); i++) {
Object transactionItem = callbacks.get(i);
//判断是不是LaunchActivityItem
if (transactionItem.getClass().getName().equals("android.app.servertransaction.LaunchActivityItem")) {
//获取mIntent属性
Field mIntentField = transactionItem.getClass().getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Log.e("TAG", "intent " + mIntentField.get(transactionItem));
Intent mIntent = (Intent) mIntentField.get(transactionItem);
Intent oldIntent = mIntent.getParcelableExtra("old_intent");
mIntentField.set(transactionItem, oldIntent);
// mIntent.setComponent(oldIntent.getComponent()); 这种方式同样有效
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8