【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 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 {
    @Override
    public 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.
     */
    @Override
    public 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 activity
        if (!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



目录
相关文章
|
10天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
1月前
|
存储 Android开发 开发者
深入理解安卓应用开发的核心组件
【10月更文挑战第8天】探索Android应用开发的精髓,本文带你了解安卓核心组件的奥秘,包括Activity、Service、BroadcastReceiver和ContentProvider。我们将通过代码示例,揭示这些组件如何协同工作,构建出功能强大且响应迅速的应用程序。无论你是初学者还是资深开发者,这篇文章都将为你提供新的视角和深度知识。
|
1月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
86 0
|
1月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
1月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
46 6
|
27天前
|
Android开发
我是一位Android工程师,用通义灵码的AS插件做开发工作助手,对比之前没有灵码,现在提效了60%
我是一位Android工程师,用通义灵码的AS插件做开发工作助手,对比之前没有灵码,现在提效了60%
38 0
|
2月前
|
存储 开发框架 数据可视化
深入解析Android应用开发中的四大核心组件
本文将探讨Android开发中的四大核心组件——Activity、Service、BroadcastReceiver和ContentProvider。我们将深入了解每个组件的定义、作用、使用方法及它们之间的交互方式,以帮助开发者更好地理解和应用这些组件,提升Android应用开发的能力和效率。
198 5
|
Android开发
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )(二)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )(二)
138 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )(三)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )(三)
271 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )(二)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )(二)
193 0