【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )
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 插件化框架 ( Hook Activity 啟動流程 | 反射獲取 IActivityManager 對象 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | AMS 啟動前使用動態代理替換掉插件 Activity 類 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | 主線程創建 Activity 實例之前使用插件 Activity 類替換占位的組件 )
文章目錄
- Android 插件化系列文章目錄
- 一、插件包 Activity 啟動原理
- 二、分析主線程中創建 Activity 實例源碼
- 1、LaunchActivityItem
- 2、ActivityThread
- 三、使用 Hook 技術在主線程創建 Activity 實例之前使用插件 Activity 類替換占位的組件
- 1、反射獲取 ActivityThread 類
- 2、反射獲取 ActivityThread 單例對象
- 3、反射獲取 mH 字段
- 4、反射獲取 mH 對象
- 5、反射獲取 Handler 中的 mCallback 字段
- 6、通過反射替換 Handler 中的 mCallback 成員
- 7、完整代碼示例
- 四、用于替換 ActivityThread 中 mH 中的 mCallback 靜態代理類
- 1、獲取 ClientTransaction 類
- 2、驗證 msg.obj 類型是否合法
- 3、反射獲取 mActivityCallbacks 字段
- 4、反射獲取 mActivityCallbacks 成員對象
- 5、使用插件 Activity 對應的 Intent 替換 LaunchActivityItem 類中的 mIntent 字段
- 6、完整代碼示例
- 五、Hook Activity 啟動流程涉及的完整代碼
- 六、博客資源
一、插件包 Activity 啟動原理
使用動態代理 , 替換 android.app.ActivityManager 中的 private static final Singleton IActivityManagerSingleton 成員的 mInstance 成員 ;
注意 : 該操作一定要在 AMS 啟動之前將原來的 Intent 替換掉 , 使用占坑的 Activity 替換插件包中的 Activity , 之后 AMS 執行完畢 , 執行到主線程 實例化 Activity 對象之前 , 還要替換回去 ;
插件包組件啟動方式 : 使用 Intent 啟動插件包時 , 一般都使用隱式啟動 ; 調用 Intent 的 setComponent , 通過包名和類名創建 Component , 這樣操作 , 即使沒有獲得 Activity 引用 , 也不會報錯
該插件包中的 Activity 沒有在 “宿主” 應用中注冊 , 因此啟動報錯 ;
AMS 會干掉沒有注冊過的 Activity , 這里先 在啟動 AMS 之前 , 設置一個已經 注冊過的 占坑 Activity ( StubActivity ) 執行啟動流程 , 在主線程生成 Activity 實例對象時 , 還需要恢復插件包中的 Activity
二、分析主線程中創建 Activity 實例源碼
1、LaunchActivityItem
ActivityManagerService 執行 Activity 啟動 , 執行了一系列的操作后 , 需要在主線程中進行實例化 , 這些操作暫時不管 , 與 Hook 無關 , 直接開始分析 主線程中的 Activity 實例化操作 ;
Activity 實例化的起點 , 從 LaunchActivityItem 源碼開始分析 ;
LaunchActivityItem 類 , 繼承了 ClientTransactionItem 類 ;
該類中重寫了 execute 方法 , 其中調用了 client.handleLaunchActivity 方法 , 就是調用的 ActivityThread 的 handleLaunchActivity 方法 ;
public class LaunchActivityItem extends ClientTransactionItem {@Overridepublic void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,mPendingResults, mPendingNewIntents, mIsForward,mProfilerInfo, client);client.handleLaunchActivity(r, pendingActions, null /* customIntent */);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);} }源碼路徑 : /frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
2、ActivityThread
ActivityThread 中的 handleLaunchActivity 方法中調用了 performLaunchActivity ,
在 performLaunchActivity 方法中 , 進行了 Activity 的實例化操作 ;
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);在 class H extends Handler 類中 , 處理 EXECUTE_TRANSACTION 信號時 , 啟動了 LaunchActivityItem 的 execute 方法 , 進而調用 ActivityThread 中的 handleLaunchActivity 方法 , 創建 Activity 實例對象 ;
這里劫持該 Handler , 將插件包 Activity 替換到原來的 Activity 中 ;
ActivityThread 的相關源碼 :
public final class ActivityThread extends ClientTransactionHandler {final H mH = new H();/** Reference to singleton {@link ActivityThread} */private static volatile ActivityThread sCurrentActivityThread;class H extends Handler {public static final int EXECUTE_TRANSACTION = 159;public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case EXECUTE_TRANSACTION:final ClientTransaction transaction = (ClientTransaction) msg.obj;mTransactionExecutor.execute(transaction);if (isSystem()) {// Client transactions inside system process are recycled on the client side// instead of ClientLifecycleManager to avoid being cleared before this// message is handled.transaction.recycle();}// TODO(lifecycler): Recycle locally scheduled transactions.break;}}}/*** Extended implementation of activity launch. Used when server requests a launch or relaunch.*/@Overridepublic Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.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 activityif (!ThreadedRenderer.sRendererDisabled) {GraphicsEnvironment.earlyInitEGL();}WindowManagerGlobal.initialize();final Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);reportSizeConfigurations(r);if (!r.activity.mFinished && pendingActions != null) {pendingActions.setOldState(r.state);pendingActions.setRestoreInstanceState(true);pendingActions.setCallOnPostCreate(true);}} else {// If there was an error, for any reason, tell the activity manager to stop us.try {ActivityManager.getService().finishActivity(r.token, Activity.RESULT_CANCELED, null,Activity.DONT_FINISH_TASK_WITH_ACTIVITY);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}return a;}/** Core implementation of activity launch. */private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {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);}if (r.activityInfo.targetActivity != null) {component = new ComponentName(r.activityInfo.packageName,r.activityInfo.targetActivity);}ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());if (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}appContext.setOuterContext(activity);activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;}r.setState(ON_CREATE);mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;} }源碼路徑 : /frameworks/base/core/java/android/app/ActivityThread.java
三、使用 Hook 技術在主線程創建 Activity 實例之前使用插件 Activity 類替換占位的組件
1、反射獲取 ActivityThread 類
// 反射獲取 ActivityThread 類Class<?> activityThreadClass = null;try {activityThreadClass = Class.forName("android.app.ActivityThread");} catch (ClassNotFoundException e) {e.printStackTrace();}
2、反射獲取 ActivityThread 單例對象
// Activity Thread 是一個單例 , 內部的單例成員是// private static volatile ActivityThread sCurrentActivityThread;// 可以直接通過 ActivityThread 類 , 獲取該單例對象// 這也是 Hook 點優先找靜態變量的原因 , 靜態變量對象容易拿到 , 通過反射即可獲取 , 不涉及系統源碼相關操作Field sCurrentActivityThreadField = null;try {sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");// 反射獲取的字段一般都要設置可見性sCurrentActivityThreadField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 獲取類的靜態變量 , 使用 字段.get(null) 即可Object activityThreadObject = null;try {activityThreadObject = sCurrentActivityThreadField.get(null);} catch (IllegalAccessException e) {e.printStackTrace();}
3、反射獲取 mH 字段
// 獲取 Activity Thread 中的 final H mH = new H() 成員字段 ;Field mHField = null;try {mHField = activityThreadClass.getDeclaredField("mH");// 設置該字段的可見性mHField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}
4、反射獲取 mH 對象
// 通過反射獲取 Activity Thread 中的 final H mH = new H() 成員實例對象Handler mHObject = null;try {mHObject = (Handler) mHField.get(activityThreadObject);} catch (IllegalAccessException e) {e.printStackTrace();}
5、反射獲取 Handler 中的 mCallback 字段
Class<?> handlerClass = null;try {handlerClass = Class.forName("android.os.Handler");} catch (ClassNotFoundException e) {e.printStackTrace();}// 通過反射獲取 final H mH = new H() 成員的 mCallback 成員字段// Handler 中有成員變量 final Callback mCallback;Field mCallbackField = null;try {//mCallbackField = handlerClass.getDeclaredField("mCallback");mCallbackField = mHObject.getClass().getDeclaredField("mCallback");// 設置字段的可見性mCallbackField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}
6、通過反射替換 Handler 中的 mCallback 成員
// 使用靜態代理類 HandlerProxy , 替換 final H mH = new H() 成員實例對象中的 mCallback 成員HandlerProxy proxy = new HandlerProxy();try {Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);mCallbackField.set(mHObject, proxy);} catch (Exception e) {e.printStackTrace();}
7、完整代碼示例
/*** 劫持 Activity Thread 的 final H mH = new H(); 成員* 該成員類型是 class H extends Handler ;* @param context*/public static void hookActivityThread(Context context) {// 反射獲取 ActivityThread 類Class<?> activityThreadClass = null;try {activityThreadClass = Class.forName("android.app.ActivityThread");} catch (ClassNotFoundException e) {e.printStackTrace();}// Activity Thread 是一個單例 , 內部的單例成員是// private static volatile ActivityThread sCurrentActivityThread;// 可以直接通過 ActivityThread 類 , 獲取該單例對象// 這也是 Hook 點優先找靜態變量的原因 , 靜態變量對象容易拿到 , 通過反射即可獲取 , 不涉及系統源碼相關操作Field sCurrentActivityThreadField = null;try {sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");// 反射獲取的字段一般都要設置可見性sCurrentActivityThreadField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 獲取類的靜態變量 , 使用 字段.get(null) 即可Object activityThreadObject = null;try {activityThreadObject = sCurrentActivityThreadField.get(null);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 Activity Thread 中的 final H mH = new H() 成員字段 ;Field mHField = null;try {mHField = activityThreadClass.getDeclaredField("mH");// 設置該字段的可見性mHField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 通過反射獲取 Activity Thread 中的 final H mH = new H() 成員實例對象Handler mHObject = null;try {mHObject = (Handler) mHField.get(activityThreadObject);} catch (IllegalAccessException e) {e.printStackTrace();}Class<?> handlerClass = null;try {handlerClass = Class.forName("android.os.Handler");} catch (ClassNotFoundException e) {e.printStackTrace();}// 通過反射獲取 final H mH = new H() 成員的 mCallback 成員字段// Handler 中有成員變量 final Callback mCallback;Field mCallbackField = null;try {//mCallbackField = handlerClass.getDeclaredField("mCallback");mCallbackField = mHObject.getClass().getDeclaredField("mCallback");// 設置字段的可見性mCallbackField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 使用靜態代理類 HandlerProxy , 替換 final H mH = new H() 成員實例對象中的 mCallback 成員HandlerProxy proxy = new HandlerProxy();try {Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);mCallbackField.set(mHObject, proxy);} catch (Exception e) {e.printStackTrace();}}
四、用于替換 ActivityThread 中 mH 中的 mCallback 靜態代理類
靜態代理 ActivityThread 中的 final H mH = new H() 成員中的 mCallback 成員 ;
該靜態代理類的主要作用是 , 在創建的 Activity 示例類之前 , 使用插件包中的 Activity 組件替換之前在 AMS 調用之前使用的 占坑用的 Activity , 就是要創建 插件包 中的 Activity 類的實例對象 ;
1、獲取 ClientTransaction 類
// 反射 android.app.servertransaction.ClientTransaction 類// 該類中有如下成員變量// private List<ClientTransactionItem> mActivityCallbacks;// 這個集合中存放的就是 android.app.servertransaction.LaunchActivityItem 類實例// 不能直接獲取 LaunchActivityItem 實例 , 否則會出錯Class<?> clientTransactionClass = null;try {clientTransactionClass =Class.forName("android.app.servertransaction.ClientTransaction");} catch (ClassNotFoundException e) {e.printStackTrace();}
2、驗證 msg.obj 類型是否合法
驗證處理的信號 , 是否是對應 LaunchActivityItem , 如果不是 , 直接退出 ;
// 驗證當前的 msg.obj 是否是 ClientTransaction 類型 , 如果不是則不進行 Intent 替換// 通過閱讀源碼可知 , 在 ActivityThread 的 mH 中, 處理 EXECUTE_TRANSACTION 信號時// 有 final ClientTransaction transaction = (ClientTransaction) msg.obj;if (!clientTransactionClass.isInstance(msg.obj)) {return true;}3、反射獲取 mActivityCallbacks 字段
// 反射獲取// private List<ClientTransactionItem> mActivityCallbacks; 成員字段Field mActivityCallbacksField = null;try {mActivityCallbacksField =clientTransactionClass.getDeclaredField("mActivityCallbacks");} catch (NoSuchFieldException e) {e.printStackTrace();}// 設置成員字段可見性mActivityCallbacksField.setAccessible(true);
4、反射獲取 mActivityCallbacks 成員對象
// 反射獲取// private List<ClientTransactionItem> mActivityCallbacks; 成員字段實例Object mActivityCallbacksObject = null;try {mActivityCallbacksObject = mActivityCallbacksField.get(msg.obj);} catch (IllegalAccessException e) {e.printStackTrace();}
5、使用插件 Activity 對應的 Intent 替換 LaunchActivityItem 類中的 mIntent 字段
遍歷 ClientTransaction 中 private List mActivityCallbacks 成員對象 , 只針對 LaunchActivityItem 類型的元素進行后續處理 ;
獲取 LaunchActivityItem 類中的 mIntent 成員變量 , 然后從其中獲取 獲取 啟動 插件包 組件的 Intent , 使用該 Intent 替換之前的 mIntent 成員 ;
// 將// private List<ClientTransactionItem> mActivityCallbacks; 成員字段實例// 強轉為 List 類型 , 以用于遍歷List mActivityCallbacksObjectList = (List) mActivityCallbacksObject;for (Object item : mActivityCallbacksObjectList) {Class<?> clazz = item.getClass();// 只處理 LaunchActivityItem 的情況if (clazz.getName().equals("android.app.servertransaction.LaunchActivityItem")) {// 獲取 LaunchActivityItem 的 private Intent mIntent; 字段// 該 Intent 中的 Activity 目前是占坑 Activity 即 StubActivity// 需要在實例化之前 , 替換成插件包中的 ActivityField mIntentField = null;try {mIntentField = clazz.getDeclaredField("mIntent");} catch (NoSuchFieldException e) {e.printStackTrace();}mIntentField.setAccessible(true);// 獲取 LaunchActivityItem 對象的 mIntent 成員 , 即可得到 Activity 跳轉的 IntentIntent intent = null;try {intent = (Intent) mIntentField.get(item);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 啟動 插件包 組件的 IntentIntent pluginIntent = intent.getParcelableExtra("pluginIntent");if (pluginIntent != null) {// 使用 包含插件包組件信息的 Intent ,// 替換之前在 Ams 啟動之前設置的 占坑 StubActivity 對應的 Intenttry {mIntentField.set(item, pluginIntent);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}6、完整代碼示例
package kim.hsl.plugin;import android.content.Intent; import android.os.Handler; import android.os.Message; import android.util.Log;import java.lang.reflect.Field; import java.util.List;/*** 靜態代理 ActivityThread 中的 final H mH = new H() 成員*/ public class HandlerProxy implements Handler.Callback {public static final int EXECUTE_TRANSACTION = 159;@Overridepublic boolean handleMessage(Message msg) {if (msg.what == EXECUTE_TRANSACTION) {// 反射 android.app.servertransaction.ClientTransaction 類// 該類中有如下成員變量// private List<ClientTransactionItem> mActivityCallbacks;// 這個集合中存放的就是 android.app.servertransaction.LaunchActivityItem 類實例// 不能直接獲取 LaunchActivityItem 實例 , 否則會出錯Class<?> clientTransactionClass = null;try {clientTransactionClass =Class.forName("android.app.servertransaction.ClientTransaction");} catch (ClassNotFoundException e) {e.printStackTrace();}// 驗證當前的 msg.obj 是否是 ClientTransaction 類型 , 如果不是則不進行 Intent 替換// 通過閱讀源碼可知 , 在 ActivityThread 的 mH 中, 處理 EXECUTE_TRANSACTION 信號時// 有 final ClientTransaction transaction = (ClientTransaction) msg.obj;if (!clientTransactionClass.isInstance(msg.obj)) {return true;}// 反射獲取// private List<ClientTransactionItem> mActivityCallbacks; 成員字段Field mActivityCallbacksField = null;try {mActivityCallbacksField =clientTransactionClass.getDeclaredField("mActivityCallbacks");} catch (NoSuchFieldException e) {e.printStackTrace();}// 設置成員字段可見性mActivityCallbacksField.setAccessible(true);// 反射獲取// private List<ClientTransactionItem> mActivityCallbacks; 成員字段實例Object mActivityCallbacksObject = null;try {mActivityCallbacksObject = mActivityCallbacksField.get(msg.obj);} catch (IllegalAccessException e) {e.printStackTrace();}// 將// private List<ClientTransactionItem> mActivityCallbacks; 成員字段實例// 強轉為 List 類型 , 以用于遍歷List mActivityCallbacksObjectList = (List) mActivityCallbacksObject;for (Object item : mActivityCallbacksObjectList) {Class<?> clazz = item.getClass();// 只處理 LaunchActivityItem 的情況if (clazz.getName().equals("android.app.servertransaction.LaunchActivityItem")) {// 獲取 LaunchActivityItem 的 private Intent mIntent; 字段// 該 Intent 中的 Activity 目前是占坑 Activity 即 StubActivity// 需要在實例化之前 , 替換成插件包中的 ActivityField mIntentField = null;try {mIntentField = clazz.getDeclaredField("mIntent");} catch (NoSuchFieldException e) {e.printStackTrace();}mIntentField.setAccessible(true);// 獲取 LaunchActivityItem 對象的 mIntent 成員 , 即可得到 Activity 跳轉的 IntentIntent intent = null;try {intent = (Intent) mIntentField.get(item);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 啟動 插件包 組件的 IntentIntent pluginIntent = intent.getParcelableExtra("pluginIntent");if (pluginIntent != null) {// 使用 包含插件包組件信息的 Intent ,// 替換之前在 Ams 啟動之前設置的 占坑 StubActivity 對應的 Intenttry {mIntentField.set(item, pluginIntent);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}return false;} }
五、Hook Activity 啟動流程涉及的完整代碼
package kim.hsl.plugin;import android.content.Context; import android.os.Handler; import android.util.Log;import java.lang.reflect.Field; import java.lang.reflect.Proxy;/*** 主要職責 : Hook Activity 的啟動過程* 本工具類只針對 API Level 28 實現 , 如果是完整插件化框架 , 需要實現所有版本的 Hook 過程* 不同的版本 , Activity 的啟動過程是不同的 , 需要逐個根據 Activity 啟動源碼進行 Hook 適配*/ public class HookUtils {private static final String TAG = "HookUtils";/*** 最終目的是劫持 ActivityManagerService 的 startActivity 方法 ,* 修改 Intent 中藥啟動的 Activity 類*/public static void hookAms(Context context){// 獲取 android.app.ActivityManager 類Class<?> activityManagerClass = null;try {activityManagerClass = Class.forName("android.app.ActivityManager");} catch (ClassNotFoundException e) {e.printStackTrace();}// 獲取 android.app.ActivityManager 類 中的 IActivityManagerSingleton 屬性// private static final Singleton<IActivityManager> IActivityManagerSingleton 成員變量Field iActivityManagerSingletonField = null;try {iActivityManagerSingletonField =activityManagerClass.getDeclaredField("IActivityManagerSingleton");// 設置成員字段的可訪問性iActivityManagerSingletonField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 獲取 android.app.ActivityManager 類的靜態成員變量// private static final Singleton<IActivityManager> IActivityManagerSingleton// 直接調用 Field 字段 iActivityManagerSingletonField 的 get 方法 , 傳入 null 即可獲取Object iActivityManagerSingletonObject = null;try {iActivityManagerSingletonObject = iActivityManagerSingletonField.get(null);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 Singleton 類// ActivityManager 中的 IActivityManagerSingleton 成員是 Singleton<IActivityManager> 類型的Class<?> singletonClass = null;try {singletonClass = Class.forName("android.util.Singleton");} catch (ClassNotFoundException e) {e.printStackTrace();}// 反射獲取 Singleton 類中的 mInstance 字段Field mInstanceField = null;try {mInstanceField = singletonClass.getDeclaredField("mInstance");// 設置字段的可訪問性mInstanceField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 反射獲取 Singleton 類中的 mInstance 成員對象// 該 mInstanceObject 成員對象就是 IActivityManager// private static final Singleton<IActivityManager> IActivityManagerSingletonObject mInstanceObject = null;try {mInstanceObject = mInstanceField.get(iActivityManagerSingletonObject);} catch (IllegalAccessException e) {e.printStackTrace();}// 使用動態代理 , 替換 android.app.ActivityManager 中的// private static final Singleton<IActivityManager> IActivityManagerSingleton 成員的// mInstance 成員// 注意 : 該操作一定要在 AMS 啟動之前將原來的 Intent 替換掉// 之后還要替換回去// 使用 Intent 啟動插件包時 , 一般都使用隱式啟動// 調用 Intent 的 setComponent , 通過包名和類名創建 Component ,// 這樣操作 , 即使沒有獲得 Activity 引用 , 也不會報錯// 該插件包中的 Activity 沒有在 "宿主" 應用中注冊 , 因此啟動報錯// AMS 會干掉沒有注冊過的 Activity// 這里先在啟動 AMS 之前 , 設置一個已經 注冊過的 占坑 Activity ( StubActivity ) 執行啟動流程// 在主線程生成 Activity 實例對象時 , 還需要恢復插件包中的 Activity// IActivityManager 是接口// 這是一個 AIDL 文件生成的 , 由 IActivityManager.aidl 生成Class<?> IActivityManagerInterface = null;try {IActivityManagerInterface = Class.forName("android.app.IActivityManager");} catch (ClassNotFoundException e) {e.printStackTrace();}// 動態代理的實際代理類AmsInvocationHandler amsInvocationHandler =new AmsInvocationHandler(context, mInstanceObject);// 動態代理過程Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), // 類加載器new Class[]{IActivityManagerInterface}, // 接口amsInvocationHandler); // 代理的對象// 使用動態代理類 , 替換原來的 ActivityManager 中的 IActivityManagerSingleton 成員// 的 Singleton 類中的 mInstance 成員try {mInstanceField.set(iActivityManagerSingletonObject, proxy);} catch (IllegalAccessException e) {e.printStackTrace();}}/*** 劫持 Activity Thread 的 final H mH = new H(); 成員* 該成員類型是 class H extends Handler ;* @param context*/public static void hookActivityThread(Context context) {// 反射獲取 ActivityThread 類Class<?> activityThreadClass = null;try {activityThreadClass = Class.forName("android.app.ActivityThread");} catch (ClassNotFoundException e) {e.printStackTrace();}// Activity Thread 是一個單例 , 內部的單例成員是// private static volatile ActivityThread sCurrentActivityThread;// 可以直接通過 ActivityThread 類 , 獲取該單例對象// 這也是 Hook 點優先找靜態變量的原因 , 靜態變量對象容易拿到 , 通過反射即可獲取 , 不涉及系統源碼相關操作Field sCurrentActivityThreadField = null;try {sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");// 反射獲取的字段一般都要設置可見性sCurrentActivityThreadField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 獲取類的靜態變量 , 使用 字段.get(null) 即可Object activityThreadObject = null;try {activityThreadObject = sCurrentActivityThreadField.get(null);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 Activity Thread 中的 final H mH = new H() 成員字段 ;Field mHField = null;try {mHField = activityThreadClass.getDeclaredField("mH");// 設置該字段的可見性mHField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 通過反射獲取 Activity Thread 中的 final H mH = new H() 成員實例對象Handler mHObject = null;try {mHObject = (Handler) mHField.get(activityThreadObject);} catch (IllegalAccessException e) {e.printStackTrace();}Class<?> handlerClass = null;try {handlerClass = Class.forName("android.os.Handler");} catch (ClassNotFoundException e) {e.printStackTrace();}// 通過反射獲取 final H mH = new H() 成員的 mCallback 成員字段// Handler 中有成員變量 final Callback mCallback;Field mCallbackField = null;try {//mCallbackField = handlerClass.getDeclaredField("mCallback");mCallbackField = mHObject.getClass().getDeclaredField("mCallback");// 設置字段的可見性mCallbackField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 使用靜態代理類 HandlerProxy , 替換 final H mH = new H() 成員實例對象中的 mCallback 成員HandlerProxy proxy = new HandlerProxy();try {Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);mCallbackField.set(mHObject, proxy);} catch (Exception e) {e.printStackTrace();}}}
六、博客資源
博客資源 :
- GitHub : https://github.com/han1202012/Plugin_Hook
總結
以上是生活随笔為你收集整理的【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 插件化】Hook 插件
- 下一篇: 【Android 插件化】Hook 插件