【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )
Android 插件化系列文章目錄
【Android 插件化】插件化簡介 ( 組件化與插件化 )
【Android 插件化】插件化原理 ( JVM 內存數據 | 類加載流程 )
【Android 插件化】插件化原理 ( 類加載器 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 原理與實現思路 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 類加載器創建 | 資源加載 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 獲取插件入口 Activity 組件 | 加載插件 Resources 資源 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 運行應用 | 代碼整理 )
【Android 插件化】Hook 插件化框架 ( Hook 技術 | 代理模式 | 靜態代理 | 動態代理 )
【Android 插件化】Hook 插件化框架 ( Hook 實現思路 | Hook 按鈕點擊事件 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動過程 | 靜態代理 )
【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 一 | Activity 進程相關源碼 )
【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 二 | AMS 進程相關源碼 | 主進程相關源碼 )
【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )
【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “插件包“ 中的 Element[] dexElements )
【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “宿主“ 應用中的 Element[] dexElements )
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements | 設置合并后的 Element[] 數組 )
【Android 插件化】Hook 插件化框架 ( 創建插件應用 | 拷貝插件 APK | 初始化插件包 | 測試插件 DEX 字節碼 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | Hook 點分析 )
文章目錄
- Android 插件化系列文章目錄
- 前言
- 一、Hook 點分析
- 二、查看 Instrumentation 源碼
- 三、分析 Instrumentation.execStartActivity 方法
- 四、分析 ActivityManager 中的源碼
- 五、博客資源
前言
在 【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “插件包“ 中的 Element[] dexElements ) 博客中介紹了從 " 插件包 " APK 文件中獲取 Element[] dexElements 流程 ;
在博客 【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “宿主“ 應用中的 Element[] dexElements ) 介紹了從 " 宿主 " 應用中獲取 Element[] dexElements 流程 ;
在博客 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements | 設置合并后的 Element[] 數組 ) 中 , 將上述從 " 插件包 " APK 文件中獲取 Element[] dexElements 和 從 " 宿主 " 應用中獲取 Element[] dexElements 獲取的兩個數組進行了合并 ;
在博客 【Android 插件化】Hook 插件化框架 ( 創建插件應用 | 拷貝插件 APK | 初始化插件包 | 測試插件 DEX 字節碼 ) 中驗證了上述加載的插件包 Dex 字節碼是否加載成功 , 并通過反射調用了插件包中的方法 ;
上面一組博客將插件包數據加載到了內存中 , 下面開始進行 Hook Activity 的操作 ,
一、Hook 點分析
在
【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 一 | Activity 進程相關源碼 )
【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 二 | AMS 進程相關源碼 | 主進程相關源碼 )
兩篇博客中 , 分析了 Activity 的啟動流程 ,
在當前應用主進程中 , 在 Activity 中執行 startActivity 方法 , 然后調用 Instrumentation 中的 execStartActivity 方法 ;
然后在 ActivityManagerService 進程中 , 執行后續操作 ; ( 具體細節看上面的兩篇博客 )
這里只需要研究 Activity 中執行 startActivity 方法的情況 , 因為插件化只涉及在 " 宿主 " 應用中 , 啟動 " 插件 " 包中的 Activity 類 , 只需要考慮這一種情況即可 ;
Activity 的所有的生命周期函數 , 都與 Instrumentation 相關 , Instrumentation 會處理 Activity 實例化等操作 ;
二、查看 Instrumentation 源碼
查看 Instrumentation 相關代碼 , 雙 Shift 搜索界面中 , 選中 " Include non-project items " 選項 , 當前的編譯版本是 28 , 因此這里選擇 API 28 中的 Instrumentation.java 源碼 ;
三、分析 Instrumentation.execStartActivity 方法
啟動 Activity 時 , 調用的是下面的 Instrumentation.execStartActivity 方法 ;
public class Instrumentation {/*** Execute a startActivity call made by the application. The default * implementation takes care of updating any active {@link ActivityMonitor}* objects and dispatches this call to the system activity manager; you can* override this to watch for the application to start an activity, and * modify what happens when it does. ** <p>This method returns an {@link ActivityResult} object, which you can * use when intercepting application calls to avoid performing the start * activity action but still return the result the application is * expecting. To do this, override this method to catch the call to start * activity so that it returns a new ActivityResult containing the results * you would like the application to see, and don't call up to the super * class. Note that an application is only expecting a result if * <var>requestCode</var> is >= 0.** <p>This method throws {@link android.content.ActivityNotFoundException}* if there was no Activity found to run the given Intent.** @param who The Context from which the activity is being started.* @param contextThread The main thread of the Context from which the activity* is being started.* @param token Internal token identifying to the system who is starting * the activity; may be null.* @param target Which activity is performing the start (and thus receiving * any result); may be null if this call is not being made* from an activity.* @param intent The actual Intent to start.* @param requestCode Identifier for this request's result; less than zero * if the caller is not expecting a result.* @param options Addition options.** @return To force the return of a particular result, return an * ActivityResult object containing the desired data; otherwise* return null. The default implementation always returns null.** @throws android.content.ActivityNotFoundException** @see Activity#startActivity(Intent)* @see Activity#startActivityForResult(Intent, int)* @see Activity#startActivityFromChild** {@hide}*/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;} }在上述方法最后 , 調用了 AMS 的 startActivity 方法 , ActivityManager.getService().startActivity() 方法最終是 ActivityManagerService 執行的 ;
由于當前主線程與 ActivityManagerService 不再同一個進程中 , 因此需要使用 Binder 進行調用 ;
四、分析 ActivityManager 中的源碼
在 ActivityManager 中的 getService 方法 , 獲取的
/*** @hide*/public static IActivityManager getService() {return IActivityManagerSingleton.get();}private static final Singleton<IActivityManager> IActivityManagerSingleton =new Singleton<IActivityManager>() {@Overrideprotected IActivityManager create() {final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);final IActivityManager am = IActivityManager.Stub.asInterface(b);return am;}};IActivityManager 是 Binder 的 Proxy , Binder 下存在 Stub 和 Proxy 兩個內部類 , Binder 生成的 Java 類時內部生成上述 Stub 和 Proxy 兩個內部類 ;
反射的時候 , 反射
final IActivityManager am = IActivityManager.Stub.asInterface(b);對象 , 最終調用 startActivity 的是 IActivityManager , 使用占坑的 Activity 隱瞞 IActivityManager , 實際上啟動我們從插件包中加載的 Activity ;
Hook 點就是 android.app.ActivityManager 的 private static final Singleton<IActivityManager> IActivityManagerSingleton成員 ;
五、博客資源
博客資源 :
- GitHub : https://github.com/han1202012/Plugin_Hook
總結
以上是生活随笔為你收集整理的【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SeeMusic】音符方块颜色设置 (
- 下一篇: 【Android 插件化】Hook 插件