在了解Android插件化原理之前滑臊,我們需要對Hook機制有一定的了解立莉,具體可以閱讀下面幾篇文章:
1.Hook機制之動態(tài)代理
2.Hook機制之Binder Hook
3.Hook機制之AMS&PMS
我們知道搓逾,要啟動一個Activity,這個Activity必須在AndroidManifest里面注冊蛹疯,如果Activity沒有注冊荸镊,是會拋android.content.ActivityNotFoundException異常的。我們不可能把插件中的每個Activity都在AndroidManifest里面注冊阅束,這樣也違背了插件化的原理呼胚。
了解Activity的啟動原理后,其實我們可以這么做:我們可以在宿主的AndroidManifest里面中注冊一個通用的Activity息裸,假設是ProxyActivity蝇更,在啟動插件Activity時先啟動這個通用的Activity,繞過AMS后呼盆,再啟動目標Activity年扩,假設是TargetActivity。
Activity的啟動過程
Activity的啟動是通過startActivity(Intent intent) 方法访圃,該方法是調用startActivityForResult方法厨幻,最后我們發(fā)現其實調用的是Instrumentation的execStartActivities方法,該方法調用的是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);
}
}
看函數ActivityManagerNative.getDefault() .startActivities方法况脆,有兩點值得注意,一個是ActivityManagerNative.getDefault()批糟,另一處是參數ApplicationThread格了。
ApplicationThread是APP進程與AMS進程通信的橋梁,是真正創(chuàng)建Activity對象并且啟動Activity的一個類徽鼎。
ApplicationThread通過調用ActivityThread的scheduleLaunchActivity方法包裝一個參數并通過Handler發(fā)送了一個消息盛末,該消息主要是用來執(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里面注冊的叹括,TargetActivity沒有注冊算墨, 在MainActivity里面,我們通過如下語句來啟動TargetActivity汁雷。
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
知道命題后净嘀,了解Activity的啟動過程后报咳,我們需要做以下兩件事。
- Hook掉ActivityManagerNative挖藏,代理ActivityManagerNative的ActivityManagerNative.getDefault()返回的IActivityManager對象暑刃,并把啟動TargetActivity的Component替換成啟動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是一個 android.util.Singleton對象; 我們取出這個單例里面的字段
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 得到ActivityManagerNative的gDefault對象膜眠,即IActivityManager對象
Object activityManager = mInstanceField.get(gDefault);
// 創(chuàng)建即IActivityManager對象的代理對象, 然后替換這個字段
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的一個Handler.Callback變量,即mH對象宵膨,通過替換mH對象架谎,在handleLaunchActivity里面替換掉ProxyActivity的參數,設置成TargetActivity的參數辟躏。
public static void hookActivityThreadHandler() throws Exception {
// 先獲當前的ActivityThread對象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
currentActivityThreadField.setAccessible(true);
Object currentActivityThread = currentActivityThreadField.get(null);
// ActivityThread一個進程只有一個,我們獲取這個對象的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的具體實現大家可以參見github的項目地址: Android插件化原理-Activity生命周期谷扣。
結語
關于Android插件化,這篇文章僅僅是講述了如何啟動一個沒在AndroidManifest里面注冊的Activity捎琐,關于Android插件化的東西很多会涎。大家可以關注下github的一個開源項目:understand-plugin-framework,對于學習Android插件話的幫助很大瑞凑。