編輯:關於Android編程
在之前一篇文章中已經講解了 Android中Hook系統服務,以及攔截具體方法的功能了,按照流程本文應該介紹如何Hook系統的AMS服務攔截應用的啟動流程操作,但是本文並不會,因為在介紹這個知識點之前,還有一件大事要做,那就是得先分析一下Android中應用的啟動流程,如果這個流程不搞清楚的話,後面沒辦法Hook的,因為你都找不到Hook點,當然Hook代理對象倒是很容易獲得,如果沒有Hook點,是沒辦法後續的操作的,所以得先把流程分析清楚了,當然現在關於應用的啟動流程的知識已經爛大街了,但是每個人都有不同的分析方式和總結方式,我始終相信我的分析流程是最清晰最有用的。
下面就先來看一下Activity的啟動流程,分析啟動流程其實很簡單,我們直接看源碼即可,我們一般在啟動Activity的時候都是使用系統的一個方法startActivity操作的,關於這個方法通過跟進代碼是在ContextImpl.java中:
這裡用到了mMainThread變量去執行的操作,再看看這個變量:
的確是ActivityThread類,這個類我們在之前分析源碼的時候多次提到它了,他是一個應用非常關鍵的一個類,首先他是一個應用的主線程,其次就是他也是一個程序的入口的地方:
後面會介紹這個入口main方法什麼時候會執行,下面繼續看ActivityThread中的getInstrumentation方法:
其實是獲取到Instrumentation類型,其實這個類相當於啟動Activity的中間者,啟動Activity中間都是由它來操作的:
看到又調用了ActivityManagerNative.getDefault方法去啟動activity了。去看看ActivityManagerNative類:
看到這裡就有點明白了吧,其實ActivityManagerNative類就是遠端服務的中間者Stub類,其實名字不叫Stub罷了,以後其實只要看到是繼承了Binder類和實現了AIDL接口類型的就是Stub類,不要關心類名了。看到他的asInterface方法的時候也是和之前的其他系統服務都是類似的,而這裡的本地端代理是ActivityManagerProxy類。
下面繼續看他的getDefault方法實現,是通過變量gDefault獲取的:
在這裡可以看到了,其實gDefalut借助Singleton實現的單例模式,而在內部可以看到先從ServiceManager中獲取到AMS遠端服務的Binder對象,然後使用asInterface方法轉化成本地化對象,其實就是ActivityManagerProxy對象。然後我們在看看上面調用了startActivityAsUser方法,其實就是調用了ActivityManagerProxy對象的這個方法:
這裡其實ActivityManagerProxy對象中的方法最終都會調用遠端服務Binder對象的transact方法,然後會轉接到遠端服務中間者ActivityManagerNative的onTransact方法中:
這裡看到會回調IActivityManager接口中的startActivityAsUser方法,而這個具體實現一般都是在遠端服務中的,這裡我們可以猜想應該是叫做ActivityManagerService中:
有一層調用了,這裡是ActivityStackSupervisor類了,這裡就不在細分了,最終會在他內部又會調用到ActivityTask類中,又多了一層,然後會調用到ActivityManagerService中的startProcessLocked方法,這裡就會執行一段命令:
看到了,其實在這個過程之前還有一個操作就是通知Zygote進程需要啟動一個新的應用進程,然後執行命令執行ActivityThread的入口方法main,所以這個main方法其實就是一個應用進程的入口方法了,下面就繼續分析main方法中都干了什麼:
在main方法中,調用了自身的attach方法:
這裡又要回到ActivityManagerService中了,然後又會調用ActivityStackSupervisor中的realStartActivityLocked方法:
而在這個方法中,會調用ProcessRecord類型的thread變量的scheduleLaunchActivity方法,而這個thread變量是IApplicationThread類型的:
哎,這裡看到了IApplicationThread可以想到,這裡可能又是一次遠端通信了:
哎,果然是,不過這裡看到這些方法會意外的發現,大部分都是和Activity的生命周期相關的,那麼可以猜想這個通信應該是操作Activity的生命周期的,在去看一下遠端服務的中間者實現了ApplicationThreadNative:
的確,這裡的實現機制都是類似的,那麼我們在上面了解了AMS的整個通信機制之後,應該知道具體的服務端實現應該是ApplicationThread中,全局搜索一下,這個類盡然是定義在ActivityThread中的:
的確,這裡是遠端的具體方法實現,那麼咋們找一下scheduleLaunchActivity方法:
最終會調用ActivityThread中的發送消息的方法:
然後會調用ActivityThread中全局的Handler類型mH發送消息
那麼咋們直接去看看消息處理邏輯:
繼續看這個方法的實現:
使用performLaunchActivity構造出一個Activity了:
在performLaunchActivity方法中還會構造一個Application出來,繼續看:
最終又調用了Instrumentation的newActivity方法:
好吧,居然在這裡構造了一個Activity實例出來了,以前使用Activity的時候,一直好奇這個Activity什麼時候創建出來的,這樣找到地方了。
然後依然在ActivityManagerService中調用了Activity的生命周期方法:
當然,其他的回調方法就不在一一列舉了,比如Application中的幾個回調方法像內存低的時候,程序異常的時候的回調也都在這裡。
到了這裡我們就大致分析完了Android中的Activity啟動流程了,從過程中看,還是非常復雜的,其實分析完了之後會發現,自己都有點迷糊了,但是一定要自己一邊分析一邊記錄,下面就是我嘔心瀝血整理的一張流程圖(圖片很大,可以下載下來查看高清原圖):
對照這張圖,下面就從頭到尾精簡的總結狠心知識點:
第一、AMS通信機制分析
首選通過ContextImpl類中的startActivity方法,進入到了Instrumentation類中的execStartActivity方法,然後進入到了ActivityManagerNative中的方法startActivity,到這裡就出現第一個轉折點和重點了,那就是AMS遠端服務架構:
在這個過程中,我們在上一篇分析系統中的剪切板服務的時候,這裡分析就不難了,主要有四個對象:
1、IActivityManager:這個是遠端服務AIDL協議接口類型,定義了很多方法
2、ActivityManagerProxy:這個是本地端中間者對象,也就是我們應用實際操作的本地化對象,他一般是由ActivityManagerNative的asInterface方法獲取到的。在這個方法中會實現IActivityManager接口的所有方法,而在具體的方法中會使用遠端服務的Binder對象方法transact發送命令給遠端中間者。
3、ActivityManagerNative:這個是遠端中間者對象,也就是我們之前分析的Stub類,只是不知道為何AMS中不叫這個名稱了,所以這裡以後分析系統服務源碼的時候,應該看到如果繼承Binder類同時實現了IXXX接口,那麼這個類就是遠端服務的中間者,他主要有兩個功能,一個是可以將遠端服務的Binder對象轉化成本地實際對象,還有一個就是可以接受本地端中間者也就是Proxy對象發送的命令,在onTransact方法中做處理,而在這個方法中其實會回調IActivityManager接口中指定的方法,而具體的接口方法實現則是在ActivityManagerService中
4、ActivityManagerService:這個是遠端服務中具體方法實現的類,在這裡就是真正的邏輯處理了,而這個類是運行在系統服務進程中的,也就是system_server中。
從上面的流程可以看到,Android中的服務大部分都符合這個規則:
IXXX是AIDL接口類型定義邏輯方法
XXXProxy是本地端代理對象,也是給應用操作的實際對象
XXXNative/XXX$Stub是遠端服務的中間者對象,主要用來處理應用發送過來的命令處理工作
XXXService是最終的服務邏輯實現方法的地方,運行在遠端進程中
第二、Activity棧機制分析
過了第一個轉折點之後,我們可以直接去ActivityManagerService中查看具體方法實現邏輯,在這裡會出現多層調用,主要是ActivityStackSupervisor類和ActivityStack類,這兩個類主要是用來處理Activity棧信息的,因為在啟動Activity的時候都會涉及到啟動模式,那麼這裡肯定要處理好應用的Activity棧信息,這裡也就是那四種經典的啟動模式實現的邏輯的地方,感興趣的同學可以仔細分析源碼。同時在這個過程中出現了幾個重要類型:
1》ActivityStack這個是管理本應用中所有Activity的棧結構。
2》ActivityRecord這個是記錄當前Activity的信息的,比如在哪進程中ProcessState,當前的狀態CurentState等,和Activity是一一對應的。
3》Task這個記錄所有Activity的信息的,這裡不會區分是哪個應用的Activity了。而這個Task就是我們經常講到的那個Activity啟動模式中的singleTask模式在啟動一個Activity的時候就會另外啟動一個Task。
4》ProcessRecord這個類記錄的是一個進程中的信息,因為一個應用中可能會包含多個進程。
第三、創建和啟動應用進程
過了Activity棧信息處理之後,會回到ActivityManagerService中的startProcessLocked方法,在這個方法中干了一件最重要的事,那就是啟動應用進程了,當然在這之前還有一步就是向Zygote進程發送請求創建應用進程,啟動應用進程其實就是調用Process類執行ActivityThread類,這樣就會執行這個類的main函數入口,到這裡我們的應用進程就算起來了,然後在看看ActivityThread中的main函數中干了什麼呢?
第四、Activity生命周期進程通信機制分析
分析到ActivityThread的main函數中,發現也是一件最重要的事就是attach操作,這個操作主要是綁定一些信息的,首先得綁定Application操作吧,然後跟進方法實現,最後在ActivityStackSupervisor類的realStartActivityLocked方法中調用了ApplicationThread的scheduleLaunchActivity方法,好了,這裡就要出現一個轉折點了,就是又要出現一個AIDL通信機制了:
這個過程其實和上面的AMS通信機制是差不多的,但是這裡的對象變了,是ApplicationThread類了,而這通信機制主要是為了Activity的生命周期服務的,上面的AMS通信機制是為了Activity啟動服務,兩者分開操作也算是比較清晰了,但是我們在這裡可以看到,這裡的服務端和客戶端通信的角色會發生變化了:
在AMS通信中,應用作為客戶端會發送指令給服務端處理
在ApplicationThread通信中,應用會作為服務端介紹來自服務端的指令
所以會發現在ActivityManagerService這個服務端類中調用的對象其實是ApplicationThreadProxy對象的。
那具體處理指令的遠端是在應用進程中,也就是ApplicationThread類,這個類是在ActivityThread中實現的。
第五、分析Activity的構造和生命周期方法
了解了ApplicationThread通信機制之後,可以去類中看看具體的生命周期方法調用邏輯了,裡面處理還是比較簡單的,是利用ActivityThread中的Handler變量作為消息發送和處理,然後在調用指定方法即可,最終會發現通過Instrumentation類中的newActivity方法構造一個Activity實例對象,然後啟動Activity的處理。然後後續會調用Activity的生命周期方法了。
到這裡我們就非常清晰的說明了Activity的啟動流程了,這裡最關鍵的點就是要理解Android中的系統服務遠端調用機制和Binder機制即可,弄清楚通信中那幾個類對象和具體關系。而這裡比較復雜的會出現了兩個進程通信操作:
同時在這個過程中我們發現了Activity啟動的過程中棧的處理,幾種Activity的啟動模式的具體邏輯處理等信息。在這個分析過程中剛開始你會覺得系統這麼設計真是夠復雜的,但是當你真的理解了,會發現這個設計真的很清晰的。AMS進程通信是為了處理Activity啟動工作,ApplicationThread進程通信是為了處理Activity的生命周期工作。
Android中了解了Activity啟動流程之後,後面我們就可以開始Hook掉系統的AMS服務,攔截Activity的啟動方法以及各種生命周期方法了,從而能夠達到我們想要的目的。作為一個Android開發者到最後都會避免不了這個Activity啟動流程的梳理工作,雖然網上的知識點已經爛大街了,但是真正自己去實踐分析效果是截然不同的,所以一定要靜下心來自己去分析一遍流程,收獲還是非常大的。
簡介 Android Universal Image Loader簡稱UIL, 其github鏈接https://github.com/nostra13/Android-
service servicemanager /system/bin/servicemanager class core user system
前言 由於接近放假,公司在趕項目所以前段LP比較忙,沒什麼時間總結和寫博客,只是准備睡覺的時候看看書,每天看的不算多,大概10多頁左右吧,不過每天堅持如此的話那也是一
寫在前面 上周把基於Redux的單頁應用開發完 緊接著就開始了ReactNative的開發。真的快得不可思議,只花了一周時間,我們兩個人就分工把APP也開發完了,並且同時