插件化讲解到实战1–类加载的解析和双亲委派机制
插件化讲解到实战2–调用插件中的类
插件化讲解到实战3–Hook的源码分析和启动插件的Activity
插件化讲解到实战4–启动Activity适配9.0,10.0等版本
Hook中文意思就是钩子,作用就是改变代码的正常执行流程。在某段SDK源码逻辑执行的过程中,通过代码手段拦截执行该逻辑,加入自己的代码逻辑。通过动态代理和反射实现Hook。
查找Hook点的原则:
1、尽量静态变量或者单例对象
2、尽量Hook public 的对象和方法
一方面这两种情况修改的少,另一方面反射的如果不是静态的方法,那么就要拿到方法对应的类的对象。
启动插件的Activity实际就运用了Hook技术,在AMS检查Activity是否在清单文件注册过之前,把插件PluginActivity换成清单文件中本来有的ProxyActivity,检查之后再换回插件PluginActivity。
1、启动插件Activity,下一步想如何将插件的Activity换成代理的Activity呢,就是改变intent:
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.enjoy.plugin", "com.enjoy.plugin.MainActivity"));
startActivity(intent);
2、
8.0源码分析如下:
startActivity调用的最终是startActivityForResult,看一下startActivityForResult 的源码:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
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);
}
}
}
看到intent在 mInstrumentation.execStartActivity被调用,这里修改intent的话,mInstrumentation这个对象不是静态的,按照原则我们继续往里找。在Instrumentation的execStartActivity源码如下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
发现在:
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
用到了intent变量,ActivityManager.getService()是AMS,我们发现getService()是静态的,是我们要找的Hook点,我们可以在此处通过动态代理修改intent。
ActivityManager.getService()的源码如下:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
可以看到,返回的是IActivityManager 对象,所以说实际上调用的startActivity就是IActivityManager 这个类里面的方法,我们直接这么写:
IActivityManager {
、、、、、
startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
}
动态代理:简单理解为将这个类复制一遍,如下:
IActivityManagerProxy {
、、、、、
startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
}
动态代理只是简单的创建了IActivityManagerProxy ,但是类的对象如果不把系统的对象替换,那么调用的还是AMS的startActivity。所以要创建一个对象把ActivityManager.getService()的对象替换,替换之后再调用startActivity就是动态代理里面的startActivity。
// 这两块代码的目的: 为了获取系统的IActivityManager对象,即mInstance -- private IActivityManager mInstance;
// 第一步获取Singleton对象,是为了获取下一步非静态的变量,要先获取这个变量的类的对象Singleton对象
Class<?> clazz = Class.forName("android.app.ActivityManager");
Field iActivityManagerSingletonField = clazz.getDeclaredField("IActivityManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
Object singleton = iActivityManagerSingletonField.get(null);
//第二步,拿到 mInstance 对象 ---》 IActivityManager对象
Class<?> signletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = signletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
final Object mInstance = mInstanceField.get(singleton);
Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
//newProxyInstance()参数:第一个类加载器,第二个参数动态代理要替换的class对象,即IActivityManager对象,第三个参数是回调invoke()方法,只要系统调用了IActivityManager对象的任何方法都会执行一次invoke()
Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{
iActivityManagerClass}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
/**
* startActivity(whoThread, who.getBasePackageName(), intent,
* intent.resolveTypeIfNeeded(who.getContentResolver()),
* token, target != null ? target.mEmbeddedID : null,
* requestCode, 0, null, options);
*/
//只有方法是startActivity的时候才回去处理,修改intent
if ("startActivity".equals(method.getName())) {
// 修改Intent
int index = 0;
//startActivity可能有重写的几种方法,所以遍历一下
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Intent) {
index = i;
break;
}
}
// 启动插件的intent
Intent intent = (Intent) objects[index];
// 改成启动代理Intent
Intent intentProxy = new Intent();
intentProxy.setClassName("com.enjoy.leo_plugin",
"com.enjoy.leo_plugin.ProxyActivity");
intentProxy.putExtra(TARGET_INTENT, intent);
objects[index] = intentProxy;
}
// 第一个参数:系统的IActivityManager对象
return method.invoke(mInstance, objects);
}
});
// 用代理对象替换系统的IActivityManager对象 ---> field
// mInstanceProxy --> 替换系统的 IActivityManager对象 ---》 反射去实现
// mInstance = mInstanceProxy
mInstanceField.set(singleton, mInstanceProxy);
到此,这三步实现了第一次Hook的替换,即把插件PluginActivity换成清单文件中本来有的ProxyActivity。下面来看ProxyActivity在AMS出来的时候替换PluginActivity。
ActivityThread的scheduleLaunchActivity的源码如下:
@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);
}
看到会执行到sendMessage(H.LAUNCH_ACTIVITY, r); H是继承的Handler,那么看H里面的LAUNCH_ACTIVITY是如何执行的。
如下:
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, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
///省略无关代码
}}
到这里可以看到,系统调用出来AMS之后,就会执行handleLaunchActivity方法。
我们是要找方便替换的intent,继续找,handleLaunchActivity源码如下:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
performPauseActivityIfNeeded(r, reason);
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
然后进入performLaunchActivity:
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);
}
///省略无关代码
}
找到了intent,往上找发现
static final class ActivityClientRecord {
IBinder token;
int ident;
Intent intent;
String referrer;
///省略无关代码
即ActivityClientRecord.intent,我们看能不能获取到ActivityClientRecord的对象,那么就拿到了intent。
继续看源码,一级级往上找ActivityClientRecord的来源:
从performLaunchActivity,往上看到handleLaunchActivity传进来的ActivityClientRecord
继续找handleMessage,发现ActivityClientRecord 就是msg.obj,如果能拿到msg就可以了。
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, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
///省略无关代码
看一下Handler的源码:
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看到handleMessage是继承Handler必须重写的,handleMessage在dispatchMessage()调用。其实handler流程当setMessage去发送消息的时候,会执行到dispatchMessage(),dispatchMessage会执行handleMessage,然后跑到ActivityThread的handleMessage里面。
dispatchMessage中的mCallback 一般是空的,我们创建一个去替换系统的mCallback ,那么mCallback 不为空的话,会执行mCallback.handleMessage(msg),也就拿到了msg,可以进行修改,相当于修改了 handleMessage(msg);中的msg,也就是修改了msg.obj中的msg。
Callback–>创建一个Callback对象,替换系统的Callback–>反射
反向流程:
Callback.msg->handleMessage(msg)->msg.obj->获取ActivityClientRecord的对象->intent
其实就是:
//系统的Callback对象 --》 mh对象 --》 ActivityThread对象 — 》
// private static volatile ActivityThread sCurrentActivityThread;
继续写代码:
// sCurrentActivityThread
Class<?> clazz = Class.forName("android.app.ActivityThread");
Field sCurrentActivityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
Object activityThread = sCurrentActivityThreadField.get(null);
// mh对象
Field mHField = clazz.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mH = (Handler) mHField.get(activityThread);
Class<?> handlerClass = Class.forName("android.os.Handler");
Field mCallbackField = handlerClass.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message message) {
switch (message.what) {
//H中LAUNCH_ACTIVITY=100
case 100:
// 拿到了message
// ActivityClientRecord的对象 --- msg.obj
try {
//拿到intent的field对象
Field intentField = message.obj.getClass().getDeclaredField("intent");
//设置作用域
intentField.setAccessible(true);
// 启动代理 intent
Intent intentProxy = (Intent) intentField.get(message.obj);
// 启动插件的intent
Intent intent = intentProxy.getParcelableExtra(TARGET_INTENT);
if (intent != null) {
intentField.set(message.obj, intent);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return false;
}
};
// 系统的callback = 自己创建的callback
mCallbackField.set(mH, callback);
完整代码:
HookUtil.java:
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HookUtil {
private static String TARGET_INTENT = "target_Intent";
public static void hookAMS() {
// 动态代理需要替换的是IActivityManager
try {
// 目的: 为了获取系统的IActivityManager对象 -- private IActivityManager mInstance;
// Singleton对象
Class<?> clazz = Class.forName("android.app.ActivityManager");
Field iActivityManagerSingletonField = clazz.getDeclaredField("IActivityManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
Object singleton = iActivityManagerSingletonField.get(null);
// mInstance 对象 ---》 IActivityManager对象
Class<?> signletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = signletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
final Object mInstance = mInstanceField.get(singleton);
Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
//newProxyInstance()参数:第一个类加载器,第二个参数动态代理要替换的class对象,即IActivityManager对象,第三个参数是回调invoke()方法,只要系统调用了IActivityManager对象的任何方法都会执行一次invoke()
Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{
iActivityManagerClass}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
/**
* startActivity(whoThread, who.getBasePackageName(), intent,
* intent.resolveTypeIfNeeded(who.getContentResolver()),
* token, target != null ? target.mEmbeddedID : null,
* requestCode, 0, null, options);
*/
//只有方法是startActivity的时候才回去处理,修改intent
if ("startActivity".equals(method.getName())) {
// 修改Intent
int index = 0;
//startActivity可能有重写的几种方法,所以遍历一下
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Intent) {
index = i;
break;
}
}
// 启动插件的intent
Intent intent = (Intent) objects[index];
// 改成启动代理Intent
Intent intentProxy = new Intent();
intentProxy.setClassName("com.enjoy.leo_plugin",
"com.enjoy.leo_plugin.ProxyActivity");
intentProxy.putExtra(TARGET_INTENT, intent);
objects[index] = intentProxy;
}
// 第一个参数:系统的IActivityManager对象
return method.invoke(mInstance, objects);
}
});
// 用代理对象替换系统的IActivityManager对象 ---> field
// mInstanceProxy --> 替换系统的 IActivityManager对象 ---》 反射去实现
// mInstance = mInstanceProxy
mInstanceField.set(singleton, mInstanceProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void hookHandler() {
//系统的Callback对象 --》 mh对象 --》 ActivityThread对象 --- 》
// private static volatile ActivityThread sCurrentActivityThread;
try {
// sCurrentActivityThread
Class<?> clazz = Class.forName("android.app.ActivityThread");
Field sCurrentActivityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
Object activityThread = sCurrentActivityThreadField.get(null);
// mh对象
Field mHField = clazz.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mH = (Handler) mHField.get(activityThread);
Class<?> handlerClass = Class.forName("android.os.Handler");
Field mCallbackField = handlerClass.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message message) {
switch (message.what) {
//H中LAUNCH_ACTIVITY=100
case 100:
// 拿到了message
// ActivityClientRecord的对象 --- msg.obj
try {
//拿到intent的field对象
Field intentField = message.obj.getClass().getDeclaredField("intent");
//设置作用域
intentField.setAccessible(true);
// 启动代理 intent
Intent intentProxy = (Intent) intentField.get(message.obj);
// 启动插件的intent
Intent intent = intentProxy.getParcelableExtra(TARGET_INTENT);
if (intent != null) {
intentField.set(message.obj, intent);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return false;
}
};
// 系统的callback = 自己创建的callback
mCallbackField.set(mH, callback);
} catch (Exception e) {
e.printStackTrace();
}
// 用我们创建的Callback对象,替换系统的Callback对象
}
}
MyApplication.java:
import android.app.Application;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HookUtil.hookAMS();
HookUtil.hookHandler();
}
}
本篇基于8.0,下一篇会适配其他。
本篇基于8.0,下一篇会适配其他。
本篇基于8.0,下一篇会适配其他。
参考:
https://www.jianshu.com/p/74c12164ffca