Hook機制學(xué)習(xí)(四) - Activity生命周期管理

weishu

一 :需要對Activity生命周期進行管理的原因及解決方案

原因: 在Android平臺上使用ClassLoader把插件的Activity,Service加載進來時企软,加載進來的Activity和Service是普通的類,是沒有生命周期的檐束,因為Activity,Service等組件的生命周期是由AMS管理的。所以動態(tài)加載Activity首先要解決的一個問題就是對Activity生命周期進行管理夭拌。
解決方案: 使用代理的思想规阀,要啟動一個插件Activity首先啟動一個代理的StubActivity恒序,StubActivity注冊在Host程序中。再在合適的時機把StubActivity替換成插件Activity谁撼,以此來突破必須在注冊Activity的限制AndroidManifest限制歧胁。

二: Activity啟動流程

具體流程可以去看源碼或者閱讀《Android藝術(shù)探索這本書》
簡化總結(jié)如下

Activity啟動流程

三:Hook點選擇及Hook方法

選擇Hook點
**1 把TargetActivity替換成StubActivity (Hook掉ActivityManagerProxy)
**選擇在啟動流程進入到system_server進程之前,Hook掉ActivityManagerNative.getDefault()的返回值(ActivityManagerProxy)。這樣當Activity的流程走到ActivityManagerNative.getDefault().startActivity時与帆,方法會進入到InvocationHandler的invoke內(nèi)部了赌,在這個方法內(nèi)部選擇替換掉ActivityManagerProxy.startActivity()的Intent參數(shù),使得Intent顯示啟動目標Activity為StubActivity玄糟,因為StubActivity在AndroidManifest文件中注冊過勿她,所以能通過AMS的真實性校驗。

Hook startActivity()方法阵翎,選擇替換掉Intent參數(shù)

if ("startActivity".equals(method.getName())) {
    // 只攔截這個方法
    // 替換參數(shù), 任你所為;甚至替換原始Activity啟動別的Activity偷梁換柱
    // API 23:
    // public final Activity startActivityNow(Activity parent, String id,
    // Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
    // Activity.NonConfigurationInstances lastNonConfigurationInstances) {

    // 找到參數(shù)里面的第一個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的啟動流程比較熟悉逢并,可以發(fā)現(xiàn)當啟動流程由AMS進程轉(zhuǎn)到App進程時,通過ApplicationThread進行Binder IPC郭卫,這個時候ApplicationThread里面的ScheduleLaunchActivity會被調(diào)用砍聊,且運行在App進程的Binder線程池,這個方法通過H Handler發(fā)送msg轉(zhuǎn)發(fā)到ActivityThread里面的handleLaunchActivity贰军。
仔細觀察Handler的dispatchMessage方法可以發(fā)現(xiàn) msg.callback的優(yōu)先級大于mCallback大于handleMessage. 因為msg.callback我們沒辦法預(yù)知玻蝌,所以可以選擇Hook掉mCallback,當msg.what=LAUNCH_ACTIVITY時词疼,選擇將Intent的顯示啟動目標為TargetActivity俯树,然后就會順利的創(chuàng)建出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;
        // 根據(jù)源碼:
        // 這個對象是 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 {
            // 把替身恢復(fù)成真身
            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();
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贰盗,一起剝皮案震驚了整個濱河市许饿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舵盈,老刑警劉巖陋率,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秽晚,居然都是意外死亡瓦糟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門爆惧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狸页,“玉大人,你說我怎么就攤上這事扯再∩衷牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵熄阻,是天一觀的道長斋竞。 經(jīng)常有香客問我,道長秃殉,這世上最難降的妖魔是什么坝初? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任浸剩,我火速辦了婚禮,結(jié)果婚禮上鳄袍,老公的妹妹穿的比我還像新娘绢要。我一直安慰自己,他們只是感情好拗小,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布重罪。 她就那樣靜靜地躺著,像睡著了一般哀九。 火紅的嫁衣襯著肌膚如雪剿配。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天阅束,我揣著相機與錄音呼胚,去河邊找鬼。 笑死息裸,一個胖子當著我的面吹牛蝇更,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播界牡,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼簿寂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宿亡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纳令,失蹤者是張志新(化名)和其女友劉穎挽荠,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體平绩,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡圈匆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捏雌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跃赚。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖性湿,靈堂內(nèi)的尸體忽然破棺而出纬傲,到底是詐尸還是另有隱情,我是刑警寧澤肤频,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布叹括,位于F島的核電站,受9級特大地震影響宵荒,放射性物質(zhì)發(fā)生泄漏汁雷。R本人自食惡果不足惜净嘀,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侠讯。 院中可真熱鬧挖藏,春花似錦、人聲如沸厢漩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袁翁。三九已至柴底,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粱胜,已是汗流浹背柄驻。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留焙压,地道東北人鸿脓。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像涯曲,于是被迫代替她去往敵國和親野哭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容