Android开发;Activity-Hook你了解多少?一起来debug
享學課堂特邀作者:周周
轉載請聲明出處!
前言
手把手講解系列文章,是我寫給各位看官,也是寫給我自己的。文章可能過分詳細,但是這是為了幫助到盡量多的人,畢竟工作5,6年,不能老吸血,也到了回饋開源的時候。
這個系列的文章:
1、用通俗易懂的講解方式,講解一門技術的實用價值
2、詳細書寫源碼的追蹤,源碼截圖,繪制類的結構圖,盡量詳細地解釋原理的探索過程
3、提供Github 的 可運行的Demo工程,但是我所提供代碼,更多是提供思路,拋磚引玉,請酌情cv
4、集合整理原理探索過程中的一些坑,或者demo的運行過程中的注意事項
5、用gif圖,最直觀地展示demo運行效果
如果覺得細節(jié)太細,直接跳過看結論即可。本人能力有限,如若發(fā)現(xiàn)描述不當之處,歡迎留言批評指正。
學到老活到老,路漫漫其修遠兮。與眾君共勉 !
引子
HOOK系列是 今年年初大概3月份寫的,其中《手把手講解 Android Hook-實現(xiàn)無清單啟動Activity》 Demo地址為:https://github.com/18598925736/ActivityHookDemo/tree/startActivityWithoutRegiste
當時是基于最新的SDK 28 android 9 進行的hook,但是近期有一位朋友提出,在SDK 28的設備上,hook之后會導致作為 LauncherActivity的生命周期完全失效。并且在SDK 29 android10的設備上,會崩潰。這位朋友解決了崩潰的問題,在此對他( github名為:fangding)表示感謝!
崩潰的問題我大致看過,也驗證過,沒有問題,已經合并到 開發(fā)分支上,很簡單,只是SDK 29改了一些類名,各位可以到 github上去自行查看。現(xiàn)在要解決的是生命周期失效的問題。
聲明一個debug源碼的坑
hook開發(fā)的初期,一般不要用真機。因為真機的系統(tǒng)都是經過了手機廠家深度定制的,如果你想要進行代碼debug,使用真機做不到的,因為代碼的行數(shù)根本對應不上。推薦使用谷歌原生的模擬器。
本文采用的是 android 9 sdk 28 谷歌原生androidStudio自帶AVD模擬器。
適合閱讀的人群
如果你對hook 有概念,并且對具體如何去hook有 興趣深入了解,那么這篇文章可以幫到你很多。
正文
-
bug 表征
-
源碼探索
-
解決方案
-
完美效果
-
可能隱患
bug 表征
Demo :https://github.com/18598925736/ActivityHookDemo/tree/startActivityWithoutRegiste 請切換到 git時間點:945df9``git checkout945df9如果結果為:HEADisnow at945df96使用androidX 則切換成功。這里是,已經出現(xiàn)問題的版本節(jié)點。
運行Demo,啟動as自帶模擬器 sdk28版本。進行跳轉,
然后發(fā)現(xiàn),生命周期函數(shù)并不執(zhí)行。
跳轉過程中,只出現(xiàn)了 onCreate onStart onResume, 照理說,跳轉之后應該有 onPause onStop. 并且我回到這個Activity時,應該會有 onRestart onStart onResume, 但是也沒有。
源碼探索
為什么生命周期函數(shù)都不執(zhí)行了?要找到這個原因,我必須先弄清楚一個問題: Activity的生命周期函數(shù)到底是由誰來調用的。
前期準備:
這里我不使用Demo工程,而是另外自己新建一個工程,寫一個普通的startActivity跳轉(這個我就不貼代碼了). 因為我們要觀察的是正常跳轉。
開工,進入源碼(SDK 28 注意,app module的sdk也要28,必須用 androidStudio自帶的AVD SDK 28模擬器才能 debug ):(為了確保源碼探索的完整流程,我們從 startActivity開始 . )
這里產生2個分支,但是仔細觀察之后,其實他們最終都走到了同一段邏輯:
Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, child,intent, requestCode, options); if(ar != null) {mMainThread.sendActivityResult(mToken, child.mEmbeddedID, requestCode,ar.getResultCode(), ar.getResultData()); }來解析這一段邏輯:
兩句代碼,一個是 mInstrumentation.execStartActivity
看來這一段并沒有涉及到Activity生命周期函數(shù)的邏輯。那么,看下一段:
mMainThread.sendActivityResult ,從 mInstrumentation.execStartActivity 執(zhí)行之后,得到了一個 ar,現(xiàn)在把這個 ar 交給mMainThread(ActivityThread類的對象),于是,進入 ActivityThread源碼:
這里的 scheduleTransaction方法,在ActivityThread的父類 ClientTransactionHandler中:
看到sendMessage,就懷疑,這里可能和 Handler扯上關系了。
還記不記得 ActivityThread的父類 ClientTransactionHandler scheduleTransaction()方法中 sendMessage(ActivityThread.H.EXECUTE_TRANSACTION,transaction); 用到了 ActivityThread.H.EXECUTE_TRANSACTION. 我們在 HextendsHandler中找到這個switch case的分支:
一共就兩句代碼可能和Activity的生命周期函數(shù)調用有關,那么我有理由懷疑就是這一段代碼在執(zhí)行 生命周期函數(shù). 那么 如何驗證我的猜想是否成立? 答:debug源碼(前面之所以要源碼版本,AVD模擬器版本,項目版本gradle SDK版本都寫成28,就是為了這里debug)加上斷點之后,開始debug,按下跳轉按鈕, 我們發(fā)現(xiàn)了驚人的現(xiàn)象:
一次跳轉,我們debug發(fā)現(xiàn)了3個可能和生命周期函數(shù)有關的細節(jié):PauseActivityItem , ResumeActivityItem, StopActivityItem,這3個是不是分別對應了 Activity的3個生命周期函數(shù)?繼續(xù)探索:找到 TransactionExecutor類的 execute()方法:
我們需要跟蹤的是 transaction參數(shù) (因為這里只有一個參數(shù)…不跟蹤它跟蹤誰呢) 然而,這里,使用到這個參數(shù)的是兩個方法, executeCallbacks() 和 executeLifecycleState(), 而,在這兩個方法中,我都找到了類似下面這樣的代碼:
finalActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest(); item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions);推斷出,生命周期函數(shù)一定和 ActivityLifecycleItem的 execute()和 postExecute()有關,還記不記得之前我們debug出來的 PauseActivityItem , ResumeActivityItem, StopActivityItem . 這3個類就是 ActivityLifecycleItem的子類,進去看看:
debug 一下:
發(fā)現(xiàn)了 ActivityThread,自然就聯(lián)想到它的 HextendsHandler ,ok, 就快接近真相了,表激動,暫且壓制一下,我們還沒有找到真憑實據(jù)。
又是一個抽象方法,直接找他的子類 ActivityThread,
終于接近真相了,這里已經很明顯了,參數(shù)是Activity對象,并且執(zhí)行了 activity.performPause().
真相大白,原來一個Activity的生命周期函數(shù) onPause是這么調用的,繞了一大圈,最終我們重寫的 onPause()方法才被執(zhí)行。
小結論
從我們startActivity開始,如果用一張圖來展示 Activity生命周期函數(shù)如何被執(zhí)行。無謂的繞繞繞去的省略中間環(huán)節(jié),只展示重點環(huán)節(jié),那就是這樣。
解決方案
現(xiàn)在可以運行我的Demo工程,注意 請切換到 git時間點:945df9, 按照上面的步驟去debug一下,結果發(fā)現(xiàn),
上一章節(jié)中圖示的正常現(xiàn)象 PauseActivityItem , ResumeActivityItem, StopActivityItem,在這里并未看到,或者說,這里 EXECUTE_TRANSACTION 分支缺失了。肯定是因為我們hook的代碼導致 ActivityThread的 H mH=newH(), classHextendsHandler 的 voidhandleMessage(Messagemsg) 部分 switchcase 沒有執(zhí)行。
既然已經確定是 ActivityThread的 mH 有問題, 那么應該檢查的,則是 hook mH的時候。
現(xiàn)在進入hook代碼:
回顧一下handler的責任鏈模式:
按照我通常的hook思路,mH通常執(zhí)行的是 第三級 成員函數(shù) handlerMessage(msg)的邏輯,我 hook一下,給mH的成員變量 mCallback賦值。 然后可以通過 return 返回值來控制要不要繼續(xù)執(zhí)行 原 handlerMessage(msg)的邏輯。如果 mCallback.handlerMessage(msg)返回了true,那么就沒有后續(xù)了, handlerMessage(msg)永遠不會執(zhí)行。如果是 returnfalse,handlerMessage(msg)仍會執(zhí)行。
已經很接近真兇了。我確定是 mCallback.handlerMessage(msg) 的 returntrue導致的問題。就檢查一下我hook的時候,哪里 returntrue了。Debug一下:
這里 list.size()是0,剛好這里 returntrue了。這里 return一下,是因為源碼中使用了 list.get(0),我不能讓它在list為0的情況下去 get(0). 對,就是這么單純,沒有別的想法。
完美效果
行動吧,把 這里的return true 改為 return false。然后再 重新運行,觀察日志,依然是從1跳轉到2。
日志如下:
生命周期函數(shù)已經完整。問題解決!
可能隱患
問題解決,可喜可賀。當我興高采烈地想在新買的華為mate30手機上試驗效果時,發(fā)現(xiàn)。正常的Activity跳轉和hook之后的跳轉速度截然不同. 肉眼可見的速度差別,hook之后慢了不止一拍。其他手機尚未發(fā)現(xiàn)。也不知道是不是華為底層做了什么事情。總之,這又是下一階段應該考慮的問題了。
結語
技術研究就是這樣,問題是無止境的,優(yōu)化是無止境的,一項技術的誕生,永遠會伴隨這無窮無盡的優(yōu)化,重構,升級,增強,擴展。學習也是如此,所謂活到老學到老,技術人應該保持對技術的熱情,執(zhí)著和追求,堅持學習。像是今天Activity 生命周期函數(shù)是如何被調用的,以前只是疑惑,現(xiàn)在終于解開謎團,完完全全抽絲剝繭,得到真相。
所謂坑坑更健康,做技術不可以害怕坑坑洞洞,有坑,解決了坑,自己才能有收獲。而且類似這種問題,我解決問題,就是將true改為false,花了1秒。但是我檢查問題,找出真相的過程,花了1天。我相信工作中類似這種問題,不在少數(shù)。在沒有足夠了解核心代碼邏輯的情況下,去編程,很有可能出一些細節(jié)性的小錯誤,這些錯誤往往是致命的。 所以,雖然SDK系統(tǒng)源碼,一些第三方庫源碼,很大,很復雜,很多彎彎繞繞,各種回掉,各種映射,各種設計模式,看上去很可怕,但是我們沒有退路,退縮不前只會讓35歲被離職的風險加大。花點時間去補充基礎知識的缺失,鼓起勇氣去讀源碼,只要掌握正確的方法,也許能在源碼的世界中找到一片不一樣的天空。
2019又一年過去了,與 各位技術人,共勉!
喜歡本文的話可以關注我們的官方賬號,第一時間獲取資訊。
你的關注是對我們更新最大的動力哦~
最后
給大家送一個小福利
資料都是免費分享的,附送高清腦圖,高清知識點講解教程,以及一些面試真題及答案解析。送給需要的提升技術、準備面試跳槽、自身職業(yè)規(guī)劃迷茫的朋友們。點我免費領取!!!
轉存中…(img-PvzvTlZK-1623556289498)]
資料都是免費分享的,附送高清腦圖,高清知識點講解教程,以及一些面試真題及答案解析。送給需要的提升技術、準備面試跳槽、自身職業(yè)規(guī)劃迷茫的朋友們。點我免費領取!!!
[外鏈圖片轉存中…(img-x6M0Sz3i-1623556289498)]
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的Android开发;Activity-Hook你了解多少?一起来debug的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 疯狂涨知识!「高并发秒杀」微信抢红包实战
- 下一篇: Android架构师谈:View-Pag