大話插件化系列目錄
插件化(一) 插件化思想與類加載
插件化(二) 插件化Activity的啟動
插件化(三) 插件資源加載
啟動Activity
我們啟動Activity的方式
正常一個進程app
startActivity(new Intent(MainActivity.this,ProxyAcitvity.class));
啟動其他進程
Intent intent = new Intent();
intent.setComponent(new ComponentName("top.zcwfeng.plugin",
"top.zcwfeng.plugin.MainActivity"));
但是我們啟動的時候都需要進行注冊。在AMS(ActivityManagerService)中進行注冊。
APP----AMS----APP
所以我們用到的技術局勢Hook: 通過 反射 和 動態代理實現。
如何查找Hook點和思路
Activity------>AMS
查找源碼的Hook點
Activity#startActivity 方法查看
Activity#startActivityForResult 三個參數方法
instrumentation 這個位置是個hook點,但是我們繼續看看有沒有更輕松
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);
}
}
}
繼續進入Instrumentation#execStartActivity
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);
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 != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
找到 靜態方法,并且有Intent相關的
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
這里讓我們容易想到,可以用動態代理去修改Intent。反射對于靜態方法比較容易。所以這里是突破口。
接口+實現,比較容易想到
source 26——8.0源碼中
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
反射拿到IActivityManager 獲取 Singleton 對象
ActivityManager.getService()---靜態方法,后去返回---IActivityManager
IActivityManger 對象---IActivityManagerSingleton get 獲取---Singleton<T>#private T mInstance
我們的proxyInstance 替換系統的 mInstance 對象
mInstance 非靜態的 -- Singleton的對象 ---- IActivityManagerSingleton 是靜態的
public static void hookAMS() {
try {
// 獲取 Singleton 對象
Class<?> clazz = Class.forName("android.app.ActivityManager");
Field singletonField = clazz.getDeclaredField("IActivityManagerSingleton");
singletonField.setAccessible(true);
Object singleton = singletonField.get(null);
// 獲取 IActivityManager 對象
Class<?> singletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object mInstance = mInstanceField.get(singleton);
Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{iActivityManagerClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//TODO Intent 的修改
//TODO Intent 的修改---進行過濾
if ("startActivity".equals(method.getName())) {
int index = -1;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
index = i;
break;
}
}
Intent intent = (Intent) args[index];
Intent proxyIntent = new Intent();
proxyIntent.setClassName("top.zcwfeng.zcwplugin",
"top.zcwfeng.zcwplugin.ProxyActivity");
intent.putExtra(TARGET_INTENT, intent);
args[index] = proxyIntent;
}
//iActivityManager 對象
return method.invoke(mInstance,args);
}
});
// TODO: 替換
//proxyInstance.startActivity()
// ActivityManager.getService() 替換成ProxyActity Instance
mInstanceField.set(singleton, proxyInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
Activity 啟動
AMS----->ApplicationThread
Hook Handler
ActivityThread------>Activity
ActivityThread#scheduleLaunchActivity----->sendMessage--->H
所以我們要Hook Handler
public static final int LAUNCH_ACTIVITY = 100;
我們的目標還是找Intent 先關方便替換的地方
繼續搜索
ActvityThread#handleLaunchActivity-->performLaunchActivity
-----> r.intent.getComponent();
找到 Intent的方便替換的地方 --- 在這個類 ActivityClientRecord 里面 --- Intent 是非靜態 -- 獲取 ActivityClientRecord 對象(關鍵點)
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
看到這個,所以 r ---- 相當與msg.obj
源碼中Handler 對象H 是 final H mH = new H();
因此我們需要到Handler#handlerMessage-------->
Handler 源碼
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
調用handlerMessage 之前,我們會執行mCallback
所以我們可以借助mCallback
mH 創建沒有構造賦值過,所以 系統的mCallback == null
思路:
創建 mCallback 替換系統的 -- 從而拿到 msg --- msg.obj -- intent
想要拿到Handler mCallBack 因為不是靜態,我們就要拿到Handler,handler就是H類,mH 不是靜態,我們就需要ActivityThread 找到
private static volatile ActivityThread sCurrentActivityThread;
靜態的反射比較方便拿到。
hookHandler
public static void hookHandler() {
// 拿到handler對象 mh,非靜態,拿到ActivityThread是靜態的
try {
Class<?> clazz = Class.forName("android.app.ActiityThread");
//獲取 ActivityThread 對象
Field activityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
activityThreadField.setAccessible(true);
Object activityThread = activityThreadField.get(null);
//獲取 mh 對象
Field mHField = clazz.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mH = (Handler) mHField.get(activityThread);
Field callbackField = Handler.class.getDeclaredField("mCallback");
callbackField.setAccessible(true);
// 創建callback
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// 通過msg 拿到 Intent 換回 插件執行的Intent
switch (msg.what) {
case 100:
try {
Field intentField = msg.obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
// 啟動代理Intent
Intent proxyIntent = (Intent) intentField.get(msg.obj);
// 啟動插件Intent
Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
if (intent != null) {
intentField.set(msg.obj, intent);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
// 必須 return false 保證向下執行handlerMessage
return false;
}
};
// 替換系統callback
callbackField.set(mH, callback);
} catch (Exception e) {
e.printStackTrace();
}
}
適配(上面用的源代碼是8.0 上的源碼,所以我們需要適配)
適配點:
1.hookAMS
Instrumentation.java ActivityManager.java
// 獲取 Singleton 對象
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // 小于8.0
Class<?> clazz = Class.forName("android.app.ActivityManagerNative");
singletonField = clazz.getDeclaredField("gDefault");
} else {
Class<?> clazz = Class.forName("android.app.ActivityManager");
singletonField = clazz.getDeclaredField("IActivityManagerSingleton");
}
- hookHandler
API 26 H 類 從100 開始
API 28 H 類 從110 開始 生命周期從100~109 合并成了一個類 159
ClientTransaction == msg.obj ---- private List<ClientTransactionItem> mActivityCallbacks;private List<ClientTransactionItem> mActivityCallbacks; -- -- ClientTransactionItem的子類
private Intent mIntent; -- LaunchActivityItem 對象 -- private List<ClientTransactionItem> mActivityCallbacks;
-- ClientTransaction == msg.obj
try {
// 獲取 mActivityCallbacks 對象
Field mActivityCallbacksField = msg.obj.getClass()
.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List mActivityCallbacks = (List) mActivityCallbacksField.get(msg.obj);
for (int i = 0; i < mActivityCallbacks.size(); i++) {
if (mActivityCallbacks.get(i).getClass().getName()
.equals("android.app.servertransaction.LaunchActivityItem")) {
Object launchActivityItem = mActivityCallbacks.get(i);
// 獲取啟動代理的 Intent
Field mIntentField = launchActivityItem.getClass()
.getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Intent proxyIntent = (Intent) mIntentField.get(launchActivityItem);
// 目標 intent 替換 proxyIntent
Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
if (intent != null) {
mIntentField.set(launchActivityItem, intent);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}