【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )(一)

简介: 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )(一)

文章目录

Android 插件化系列文章目录

前言

一、分析 Activity 启动源码

1、源码分析

2、涉及到的 Activity 相关代码

二、Hook Activity 启动过程

1、分析相关 类 / 成员 / 方法 结构

2、反射获取 Activity 中的 Instrumentation mInstrumentation 成员字段

3、获取 Activity 中的 Instrumentation mInstrumentation 成员字段值

4、设置 Activity 中的 Instrumentation mInstrumentation 成员字段值

5、代理类开发

三、完整代码示例

1、主界面代码示例

2、代理类代码示例

3、跳转的界面

4、执行结果

四、博客资源

前言

上一篇博客 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 ) 简要介绍了 Hook 实现思路 , 以及使用静态代理实现了 Hook 按钮点击事件 ;


在本博客中使用 Hook 技术进行 Hook 住 Activity 启动过程 ;






一、分析 Activity 启动源码



1、源码分析


在 " 宿主 " 模块中 , 启动 " 插件 " 模块 , 调用的是 startActivity 方法 ;


如果要 Hook Activity 的启动过程 , 必须熟悉启动 Activity 的源码 , 下面开始分析 调用 startActivity 方法的源码逻辑 ;



在 Activity 中启动另外一个 Activity , 调用 void startActivity(Intent intent) 方法 ,


 

@Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }


在该 void startActivity(Intent intent) 方法中主要调用 void startActivity(Intent intent, @Nullable Bundle options) 重载方法 ;


 

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
                && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
            if (TextUtils.equals(getPackageName(),
                    intent.resolveActivity(getPackageManager()).getPackageName())) {
                // Apply Autofill restore mechanism on the started activity by startActivity()
                final IBinder token =
                        mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                // Remove restore ability from current activity
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
                // Put restore token
                intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
                intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
            }
        }
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }


在 void startActivity(Intent intent, @Nullable Bundle options) 中 , 最终调用了 void startActivityForResult(@RequiresPermission Intent intent, int requestCode) 方法 启动 Activity ;


void startActivityForResult(@RequiresPermission Intent intent, int requestCode) 方法最终也是调用 void startActivityForResult(@RequiresPermission Intent intent, int requestCode,

@Nullable Bundle options) 重载方法 , 最后一个参数设置为 null ;


 

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }


在 void startActivityForResult(@RequiresPermission Intent intent, int requestCode,

@Nullable Bundle options) 方法中 , 调用了 Instrumentation mInstrumentation 成员的 execStartActivity 方法 , 启动 Activity ;


     

Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);


通过 Hook 该 execStartActivity 方法 , 使用该方法启动的 Activity 有完整的上下文环境 ;



2、涉及到的 Activity 相关代码


Activity 相关完整代码 :


public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback,
        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
                && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
            if (TextUtils.equals(getPackageName(),
                    intent.resolveActivity(getPackageManager()).getPackageName())) {
                // Apply Autofill restore mechanism on the started activity by startActivity()
                final IBinder token =
                        mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                // Remove restore ability from current activity
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
                // Put restore token
                intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
                intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
            }
        }
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }
}



目录
相关文章
|
11天前
|
Android开发 开发者
Android UI设计中,Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等,定义在`styles.xml`。
【6月更文挑战第26天】Android UI设计中,Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等,定义在`styles.xml`。要更改主题,首先在该文件中创建新主题,如`MyAppTheme`,覆盖所需属性。然后,在`AndroidManifest.xml`中应用主题至应用或特定Activity。运行时切换主题可通过重新设置并重启Activity实现,或使用`setTheme`和`recreate()`方法。这允许开发者定制界面并与品牌指南匹配,或提供多主题选项。
19 6
|
12天前
|
Android开发 开发者
Android UI中的Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等。要更改主题
【6月更文挑战第25天】Android UI中的Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等。要更改主题,首先在`styles.xml`中定义新主题,如`MyAppTheme`,然后在`AndroidManifest.xml`中设置`android:theme`。可应用于全局或特定Activity。运行时切换主题需重置Activity,如通过`setTheme()`和`recreate()`方法。这允许开发者定制界面以匹配品牌或用户偏好。
15 2
|
9天前
|
Android开发 UED 开发者
Android Activity启动模式详解
Android Activity启动模式详解
13 0
|
9天前
|
Android开发 UED
Android Activity的生命周期详解
Android Activity的生命周期详解
9 0
|
9天前
|
Android开发
Android Activity跳转详解
Android Activity跳转详解
14 0
|
Android开发
Android面试题:bindService获取代理是同步还是异步
Android面试题:bindService获取代理是同步还是异步
399 0
Android面试题:bindService获取代理是同步还是异步
|
9天前
|
安全 Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的深度对比
在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。本文旨在通过数据驱动的分析方法,深入探讨这两大操作系统在开发环境、用户界面设计及市场表现等方面的差异。引用最新的行业报告和科研数据,结合技术专家的观点,本文将提供对开发者和市场分析师均有价值的洞见。
|
12天前
|
Java 开发工具 Android开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着半壁江山。本文将深入探讨这两个平台在开发过程中的关键差异点,包括编程语言、开发工具、用户界面设计、性能优化以及市场覆盖等方面。通过对这些关键因素的比较分析,旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和目标受众做出明智的平台选择。
|
11天前
|
监控 Android开发 iOS开发
探索Android与iOS开发的差异:平台、工具和用户体验的比较
【6月更文挑战第25天】在移动应用开发的广阔天地中,Android和iOS两大平台各领风骚,它们在开发环境、工具选择及用户体验设计上展现出独特的风貌。本文将深入探讨这两个操作系统在技术实现、市场定位和用户交互方面的关键差异,旨在为开发者提供一个全景式的视图,帮助他们在面对项目决策时能够更加明智地选择适合自己项目需求的平台。
|
11天前
|
缓存 测试技术 Shell
详细解读Android开发命令行完全攻略
详细解读Android开发命令行完全攻略
10 1