官术网_书友最值得收藏!

序一

當接到包老師邀請寫序時,我真是受寵若驚。大家都知道,作為一個程序員,寫代碼拿手那是自然的事情,文字工作實在不是我的強項,但是能給包老師的書寫序,實在是榮幸之至,更何況盛情難卻呢。

我與包老師相識是在2015年的一個關于DroidPlugin的分享會上,那會兒我還在360公司做手機助手。2014年年底到2015年年初的時候,在公司比較空閑,所以寫了一個插件化框架叫DroidPlugin,并在2015年7月份以公司的名義在GitHub上開源了出來,承蒙大家抬愛,在極短的時間內便收獲了數千顆星。因為在項目的介紹中我寫上了“免修改、免重打包、免安裝運行”的宣傳語,所以也被一些人冠以“360黑科技”,在知乎上甚至有人認為這是360的什么陰謀。不管是不是什么陰謀,但這個項目讓我認識了很多行業中的大牛(包老師就是其中一位),確實是我意料之外的事情。后來跟包老師、任玉剛老師幾位經常結成“飯醉團伙”,自然也少不了討論插件化技術。既然與包老師是因為DroidPlugin開源項目相識,而包老師這本書的內容涉及的很多技術也跟其相關,所以我還是主要介紹一下DroidPlugin項目中的相關技術。

如你所見,那會兒正是插件化技術大熱的時候,各大公司也相繼開源了自己的插件化框架,但是總結來看,所涉及的技術原理也大同小異。但是DroidPlugin在其中的確算是比較“奇葩”的一個,因為它實際不止是一個插件化框架,更多的算是一個用戶態虛擬機,后來大多數的雙開軟件也都參考了它的源碼或者原理。

要在Android上實現免安裝、免修改運行一個App,并不是一件容易的事情。因為Android系統設計和權限的限制,我們需要做很多的工作……這跟Docker不一樣,雖然都是Linux系統,但在Android上我們不能要求root權限,而Docker則沒有這些限制,因此Linux內核提供的namespace、cgroup、chroot等能力也自然可以應用在Docker中。同時因為國內各大廠商的定制系統,我們也做了大量的適配工作。雖然現在看起來這個框架還有不少缺陷,但在當時確實算是比較先進的一個框架。

DroidPlugin使用了一些比較hack的技巧,但是總結起來也就是一句話“利用hook技術實現欺上瞞下,從而達到免安裝運行的目的”。因為Android系統出于安全考慮,系統服務與App進程采用分進程設計,它們之間通訊使用binder技術,系統服務實際上是不知道App進程中運行的具體代碼,這為我們實現“欺上瞞下”提供了可能。所謂“欺上瞞下”中的“欺上”是指我們可以通過某種技術手段,攔截所有插件發向系統服務的通信,讓系統不知道插件在我們的宿主App中運行;“瞞下”是指通過攔截并模擬系統服務發向插件的通信,讓插件“以為”自己已經被安裝。這樣我們就可以模擬一個環境,讓插件運行在宿主的模擬進程中。

要做到欺上瞞下,hook技術不可缺。hook這個詞是我從Window安全技術中借用而來的,這實際上是一種函數攔截技術。在某個函數調用流程中插入我們自己的函數,實現對目標函數的參數、返回值的修改。比如某個函數調用流程為:a調用b、b調用c,那么我們可以動態攔截對b函數的調用,插入我們自己的函數h,修改后的調用流程為:a調用h, h調用b, b調用c,因為h是我們新插入的函數,由我們自己編寫邏輯,那么在h函數中調用b的時候,我們就可以修改其參數、返回值,甚至可以中斷調用流程,不調用b函數而偽造一個返回結果給a。在此過程中,a是不知道它調用的b函數已經被我們修改了。這就達到了我們“欺上瞞下”的目的。

hook技術的思想非常類似于設計模式中的代理模式和Java Spring框架中的AOP(Aspect Oriented Programming,面向切面編程)。盡管它們的實現原理完全不同,但目的卻差不多。DroidPlugin中的Hook技術實際上是使用了Java中的動態代理技術,它只是在一些關鍵點通過動態代理生成的對象替換掉系統原來的對象,從而完成了對系統通信的hook。

這其中最關鍵的是對AMS(Activity Manage Service)和PMS(Package Manage Service)以及Handler的hook。AMS負責管理Android中Activity、Service、Content Provider、Broadcast四大組件的生命周期以及各種調度工作,我們hook它可以實現對插件四大組件的管理及調度;PMS負責管理系統中安裝的所有App,我們hook它是為了讓插件以為自己已經被安裝;Handler是系統向插件傳遞消息的一個橋梁,我們hook它則是為了把系統發向宿主的消息轉發給插件。至于在DroidPlugin中看到的對其他系統服務的hook,在大多數情況下都是為了“欺上”——讓系統感知不到插件的運行。DroidPlugin還實現了一個簡單的AMS服務、一個PMS服務,將hook后的AMS和PMS系統調用轉發到我們自己的AMS和PMS服務中去,由DroidPlugin自己管理。

除此之外,DroidPlugin的另外一個特色是“占位”操作。眾所周知,在Android四大組件中除了BroadcastReceiver之外,其他如Activity三大組件都需要在AndroidManifest. xml中注冊,這是靜態的,是Android框架要求我們預先寫死的,我們沒有辦法動態地向系統注冊一個Activity或者是Service。所以插件中的Activity、Service、Content Provider則是不可能向系統真正注冊。所以我們使用了“占位”的技術,也就是說先在宿主中注冊很多的“坑位”,比如對于Activity來說,就是Activity1、Activity2、Activity3等。在我們需要啟動某插件Activity的時候,可以通過hook技術,將其替換為某個坑位,如Activity1,讓系統服務去啟動坑位Activity;而在真正的系統服務AMS回調插件進程要求插件進程去啟動坑位Activity的時候,我們再換回插件的Activity,這樣我們就實現了插件Activity的免注冊運行。當然,因為Activity的Launch Mode等各種參數問題,我們還需要做很多的細節工作,才能完美。

為了某種完美,DroidPlugin中做了大量的適配工作,這讓其初看起來復雜又臃腫,但是當了解到其中的原理和關鍵代碼后,你會發現如果僅僅是滿足“插件化”需求的話,那么其中很多適配并不必需。從現在來看,DroidPlugin實際上算是一個用戶態虛擬機的雛形,從插件化的角度來說則有些“重”了。但是它對于大家深入研究Android技術本身,則或多或少會有些幫助。

現在市面上也有各種各樣的開源插件化框架,其中很多都已經在各大公司自己的產品中長期穩定使用,滿足了各種現實的需求,它們的穩定性、可用性都還是不錯的。包老師在本書中也對其中很多插件進行了介紹剖析。

如果我們不滿足于業務研發,希望可以了解一些Android底層知識,研讀這些開源框架的源碼則大有裨益。當然,包老師的這本書是國內第一本介紹插件化技術的書籍,作為我們學習插件化技術的入門書籍,則相當合適。

張勇,2018年6月于北京

主站蜘蛛池模板: 绥化市| 扶余县| 无锡市| 宝清县| 麻城市| 丰台区| 行唐县| 苗栗县| 鸡东县| 峨边| 合作市| 平利县| 财经| 中超| 东源县| 德安县| 同江市| 陇南市| 咸阳市| 龙陵县| 红河县| 枣阳市| 鄂伦春自治旗| 金门县| 奎屯市| 澄迈县| 沈丘县| 台中市| 周口市| 壶关县| 揭西县| 涿州市| 江油市| 乐清市| 江城| 中江县| 巴中市| 大石桥市| 甘德县| 屏东市| 乌拉特中旗|