在了解Android插件化原理之前,我們需要對(duì)Hook機(jī)制有一定的了解,具體可以閱讀下面幾篇文章:
1.Hook機(jī)制之動(dòng)態(tài)代理
2.Hook機(jī)制之Binder Hook
3.Hook機(jī)制之AMS&PMS
我們知道,要啟動(dòng)一個(gè)Activity,這個(gè)Activity必須在AndroidManifest里面注冊(cè),如果Activity沒有注冊(cè),是會(huì)拋android.content.ActivityNotFoundException異常的。我們不可能把插件中的每個(gè)Activity都在AndroidManifest里面注冊(cè),這樣也違背了插件化的原理。
了解Activity的啟動(dòng)原理后,其實(shí)我們可以這么做:我們可以在宿主的AndroidManifest里面中注冊(cè)一個(gè)通用的Activity,假設(shè)是ProxyActivity,在啟動(dòng)插件Activity時(shí)先啟動(dòng)這個(gè)通用的Activity,繞過AMS后,再啟動(dòng)目標(biāo)Activity,假設(shè)是TargetActivity。
Activity的啟動(dòng)過程
Activity的啟動(dòng)是通過startActivity(Intent intent) 方法,該方法是調(diào)用startActivityForResult方法,最后我們發(fā)現(xiàn)其實(shí)調(diào)用的是Instrumentation的execStartActivities方法,該方法調(diào)用的是execStartActivitiesAsUser方法,下面摘出execStartActivitiesAsUser方法主要代碼如下:
public void execStartActivitiesAsUser(Context who, IBinder contextThread,
IBinder token, Activity target, Intent[] intents, Bundle options,
int userId) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
......
int result = ActivityManagerNative.getDefault()
.startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
token, options, userId);
checkStartActivityResult(result, intents[0]);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
看函數(shù)ActivityManagerNative.getDefault() .startActivities方法,有兩點(diǎn)值得注意,一個(gè)是ActivityManagerNative.getDefault(),另一處是參數(shù)ApplicationThread。
ApplicationThread是APP進(jìn)程與AMS進(jìn)程通信的橋梁,是真正創(chuàng)建Activity對(duì)象并且啟動(dòng)Activity的一個(gè)類。
ApplicationThread通過調(diào)用ActivityThread的scheduleLaunchActivity方法包裝一個(gè)參數(shù)并通過Handler發(fā)送了一個(gè)消息,該消息主要是用來執(zhí)行handleLaunchActivity方法,handleLaunchActivity方法里面有一句Activity a = performLaunchActivity(r, customIntent)
用來創(chuàng)建Activity,后面通過Instrumentation去執(zhí)行Activity的生命周期方法。
Hook解析
這里先給出AndroidManifest代碼,如下:
<application
android:name=".PluginApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<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=".ProxyActivity" />
</application>
ProxyActivity是在AndroidManifest里面注冊(cè)的,TargetActivity沒有注冊(cè), 在MainActivity里面,我們通過如下語句來啟動(dòng)TargetActivity。
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
知道命題后,了解Activity的啟動(dòng)過程后,我們需要做以下兩件事。
- Hook掉ActivityManagerNative,代理ActivityManagerNative的ActivityManagerNative.getDefault()返回的IActivityManager對(duì)象,并把啟動(dòng)TargetActivity的Component替換成啟動(dòng)ProxyActivity的Component。
public static void hookActivityManagerNative() throws ClassNotFoundException,
NoSuchMethodException, InvocationTargetException,
IllegalAccessException, NoSuchFieldException {
//
Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = activityManagerNative.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
//gDefault是一個(gè) android.util.Singleton對(duì)象; 我們?nèi)〕鲞@個(gè)單例里面的字段
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 得到ActivityManagerNative的gDefault對(duì)象,即IActivityManager對(duì)象
Object activityManager = mInstanceField.get(gDefault);
// 創(chuàng)建即IActivityManager對(duì)象的代理對(duì)象, 然后替換這個(gè)字段
Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(activityManager));
mInstanceField.set(gDefault, proxy);
}
- Hook掉ActivityThreadHandler,即ActivityThread的一個(gè)Handler.Callback變量,即mH對(duì)象,通過替換mH對(duì)象,在handleLaunchActivity里面替換掉ProxyActivity的參數(shù),設(shè)置成TargetActivity的參數(shù)。
public static void hookActivityThreadHandler() throws Exception {
// 先獲當(dāng)前的ActivityThread對(duì)象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
currentActivityThreadField.setAccessible(true);
Object currentActivityThread = currentActivityThreadField.get(null);
// ActivityThread一個(gè)進(jìn)程只有一個(gè),我們獲取這個(gè)對(duì)象的mH
Field mHField = activityThreadClass.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mH = (Handler) mHField.get(currentActivityThread);
Field mCallBackField = Handler.class.getDeclaredField("mCallback");
mCallBackField.setAccessible(true);
mCallBackField.set(mH, new ActivityThreadCallback(mH));
}
其中IActivityManagerHandler和ActivityThreadCallback的具體實(shí)現(xiàn)大家可以參見github的項(xiàng)目地址: Android插件化原理-Activity生命周期。
結(jié)語
關(guān)于Android插件化,這篇文章僅僅是講述了如何啟動(dòng)一個(gè)沒在AndroidManifest里面注冊(cè)的Activity,關(guān)于Android插件化的東西很多。大家可以關(guān)注下github的一個(gè)開源項(xiàng)目:understand-plugin-framework,對(duì)于學(xué)習(xí)Android插件話的幫助很大。