Hook机制学习(四) - Activity生命周期管理

weishu

一 :需要对Activity生命周期进行管理的原因及解决方案

原因: 在Android平台上使用ClassLoader把插件的Activity,Service加载进来时,加载进来的Activity和Service是普通的类,是没有生命周期的,因为Activity,Service等组件的生命周期是由AMS管理的。所以动态加载Activity首先要解决的一个问题就是对Activity生命周期进行管理。
解决方案: 使用代理的思想,要启动一个插件Activity首先启动一个代理的StubActivity,StubActivity注册在Host程序中。再在合适的时机把StubActivity替换成插件Activity,以此来突破必须在注册Activity的限制AndroidManifest限制。

二: Activity启动流程

具体流程可以去看源码或者阅读《Android艺术探索这本书》
简化总结如下

Activity启动流程

三:Hook点选择及Hook方法

选择Hook点
**1 把TargetActivity替换成StubActivity (Hook掉ActivityManagerProxy)
**选择在启动流程进入到system_server进程之前,Hook掉ActivityManagerNative.getDefault()的返回值(ActivityManagerProxy)。这样当Activity的流程走到ActivityManagerNative.getDefault().startActivity时,方法会进入到InvocationHandler的invoke内部,在这个方法内部选择替换掉ActivityManagerProxy.startActivity()的Intent参数,使得Intent显示启动目标Activity为StubActivity,因为StubActivity在AndroidManifest文件中注册过,所以能通过AMS的真实性校验。

Hook startActivity()方法,选择替换掉Intent参数

if ("startActivity".equals(method.getName())) {
    // 只拦截这个方法
    // 替换参数, 任你所为;甚至替换原始Activity启动别的Activity偷梁换柱
    // API 23:
    // public final Activity startActivityNow(Activity parent, String id,
    // Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
    // Activity.NonConfigurationInstances lastNonConfigurationInstances) {

    // 找到参数里面的第一个Intent 对象

    Intent raw;
    int index = 0;

    for (int i = 0; i < args.length; i++) {
        if (args[i] instanceof Intent) {
            index = i;
            break;
        }
    }
    raw = (Intent) args[index];

    Intent newIntent = new Intent();

    // 这里包名直接写死,如果再插件里,不同的插件有不同的包  传递插件的包名即可
    String targetPackage = "com.weishu.intercept_activity.app";

    // 这里我们把启动的Activity临时替换为 StubActivity
    ComponentName componentName = new ComponentName(targetPackage, StubActivity.class.getCanonicalName());
    newIntent.setComponent(componentName);

    // 把我们原始要启动的TargetActivity先存起来
    newIntent.putExtra(HookHelper.EXTRA_TARGET_INTENT, raw);

    // 替换掉Intent, 达到欺骗AMS的目的
    args[index] = newIntent;

    Log.d(TAG, "hook success");
    return method.invoke(mBase, args);

}

return method.invoke(mBase, args);

2 把StubActivity换回TargetActivity(Hook掉Handler.callback)
如果对于Activity的启动流程比较熟悉,可以发现当启动流程由AMS进程转到App进程时,通过ApplicationThread进行Binder IPC,这个时候ApplicationThread里面的ScheduleLaunchActivity会被调用,且运行在App进程的Binder线程池,这个方法通过H Handler发送msg转发到ActivityThread里面的handleLaunchActivity。
仔细观察Handler的dispatchMessage方法可以发现 msg.callback的优先级大于mCallback大于handleMessage. 因为msg.callback我们没办法预知,所以可以选择Hook掉mCallback,当msg.what=LAUNCH_ACTIVITY时,选择将Intent的显示启动目标为TargetActivity,然后就会顺利的创建出TargetActivity。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Hook掉CallBack

/* package */ class ActivityThreadHandlerCallback implements Handler.Callback {

    Handler mBase;

    public ActivityThreadHandlerCallback(Handler base) {
        mBase = base;
    }

    @Override
    public boolean handleMessage(Message msg) {

        switch (msg.what) {
            // ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100
            // 本来使用反射的方式获取最好, 这里为了简便直接使用硬编码
            case 100:
                handleLaunchActivity(msg);
                break;
        }

        mBase.handleMessage(msg);
        return true;
    }

    private void handleLaunchActivity(Message msg) {
        // 这里简单起见,直接取出TargetActivity;

        Object obj = msg.obj;
        // 根据源码:
        // 这个对象是 ActivityClientRecord 类型
        // 我们修改它的intent字段为我们原来保存的即可.
/*        switch (msg.what) {
/             case LAUNCH_ACTIVITY: {
/                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
/                 final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
/
/                 r.packageInfo = getPackageInfoNoCheck(
/                         r.activityInfo.applicationInfo, r.compatInfo);
/                 handleLaunchActivity(r, null);
*/

        try {
            // 把替身恢复成真身
            Field intent = obj.getClass().getDeclaredField("intent");
            intent.setAccessible(true);
            Intent raw = (Intent) intent.get(obj);

            Intent target = raw.getParcelableExtra(HookHelper.EXTRA_TARGET_INTENT);
            raw.setComponent(target.getComponent());

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容