Android在init.rc中自定義開機啟動進程(service)
原文鏈接:Android如何配置init.rc中的開機啟動進程(service)(有刪改)
前言
首先我先來解釋一下本文到底講什么的。
用一句話來說:本文講解的主要內容是,如何通過修改Android操作系統源碼,來配置一個自定義的開機啟動進程。
有些人也許會問,這有什么用?問的好,一項實用的技術必然要有用處才會有價值。
首先說明的是,如果你的工作或項目只是做一個應用程序app,那本文確實沒有什么用處。但如果你的公司做的是Android系統開發,或者本身就是一家做硬件的公司,那本文可能就會有不少用處了;
舉個例子:假如你們公司做了一台搭載Android的嵌入式設備,這台設備有某個特殊的傳感器是一般手機沒有的,傳感器屬於硬件,那想讓硬件工作就必然有驅動程序,現在我們想讓這個傳感器在設備一開機的時候就立刻啟動,那我們就需要知道如何配置一個Android的開機啟動進程了。而本文正是講這部分內容的。如果用最簡單的一句話描述本文是講什么的,那其實只要文章題目的一句話,但是其實涉及到的知識又多又雜,加上本人也處在底層開發的探索階段,所以,涉及到的知識我只講到我們能用到的深度為止,如果想深入學習,我會附上其他博主對這些知識深入分析的文章的鏈接。
需要做哪些准備工作?
首先,在硬件上,我希望你能有一塊能搭載Android系統的嵌入式開發板,比如我用的是Friendly-arm的NanoPi M3,也許你會問,一台普通的Android手機行不行,這個說實話我沒有試過,但是市面上的手機有很多權限是被廠商限制的,所以如果用手機來測試,可能會發生很多迷之問題,所以我建議還是使用一塊開發板,不一定非要和我的型號一樣,只要能跑Android就行。其次,在軟件上,我希望你准備好了一份Android系統的源碼,關於如何獲取Android的源碼我這里就不講了,網上有很多文章講這個,你可以從Google官方的渠道獲取,如果你使用開發板,一般開發板的提供商也會提供定制的Android源碼,那我們就直接從開發板的提供商的網站獲取就行了。最后,我希望你有一台裝有mac OS或者Linux操作系統的電腦,本文所開展的工作只支持以上兩種系統,不支持Windows,其實我比較推薦unbuntu 14.04,這也是我使用的開發板的官方文檔所推薦的,你當然也可以用Mac,但是說實話,我最開始開展工作時用的是搭載mac OS 10.12.02的Macbook pro 2016,各種發生迷之錯誤,其實按道理來說是可以解決的,但是由於做底層開發的人本來就不多,以及用Mac做底層開發的人就更少了,所以網上關於解決這些問題的學習資料以及文章少之又少,導致問題長時間無法解決,浪費時間,所以還是推薦使用ubuntu 14.04。
最后,閱讀本文需要哪些知識?本文盡量講的通俗且淺顯易懂,你不需要有任何底層開發的前置知識,你只需要對Android系統有一個比較全面的認識就行,你說你寫App的水平不高?這些都沒關系,都不會影響你閱讀這篇文章。但是我希望你能了解最起碼的Linux命令,不用太復雜,最基本的就行,實在不行,Windows的cmd命令總用過吧,只要會用命令行工具進入硬盤下某個目錄就行。
大體上有哪些知識點
大體上有哪些知識點,我畫了以下一張圖來描述:
這么一看,一目了然,我們需要將我們自己寫的程序(示例中我用的是C語言)將它配置給init.rc這個文件;然后通過編寫Android.mk來對它進行編譯描述,什么是編譯描述呢?我們可以這么理解,只要我們寫的這個程序的所在目錄下有Android.mk文件,它就可以和Android源碼一樣用make命令編譯;然后我們要通過SEAndroid給我們的程序授權,否則程序會因為權限問題而無法執行;以上這些都是在Android源碼中進行修改的;最后,我們將源碼編譯,刷機,運行,你親自編譯的Android操作系統就可以運行在你的開發板上,同時,你的C程序也可以跟隨Android系統的啟動而實現開機啟動。
Android源碼目錄結構介紹
我相信讀者手里已經拿到一份Android源碼了,無論它是從哪里獲得的(哪怕是同學同事拷貝給你的)。我的源碼版本是5.1.1,源碼版本對本文的影響不大,只要版本不是太老就行。我們先來對Android源碼做個簡要的介紹。打開源碼的文件夾,我們會發現有很多目錄,讓我們眼花繚亂,確實,Android系統是一個非常復雜的軟件,它必須面面俱到,所以這里面的源碼覆蓋了方方面面,想要全部把它看完是不可能的,我相信有不少人看過Linux內核源碼,光是Linux內核的源碼可能就能讓一個人一生都無法窮盡,而Linux內核只是Android的最底層,可想而知Android的源碼數量有多么龐大,所以我在這里只說幾個我們最常用的目錄以及本文會涉及到的目錄。
不少人做Android都是做應用開發,做應用開發入門以后很多人都想要進階,這時候就會買一些進階的書,這些進階的書很多都涉及Android源碼分析,比如比較火的《Android開發藝術探索》,《Andoird源碼設計模式解析與實戰》等等,我們剛學Android的時候就知道,Android系統分為四層,我們開發的應用處於Application層,而Application層的下面一層是framework層,想做好應用開發,了解一下下層機制是必不可少的,所以我剛才說的源碼分析的書籍所講解的源碼都在framework層,大家其實也能發現,這些書里所講的源碼都是java代碼。那打開Android源碼目錄,我們能看到一個framework文件夾,所以framework層的源碼就在這個文件夾下,你進去找找,可以找到不少應用開發時常用的API。
上面說的是閑話,現在我來介紹一個等一下會多次使用的一個目錄——device,點開這個目錄,我們會看到很多手機品牌的名字,比如htc啊,moto啊,samsung啊等等。這是什么意思呢?Android系統會運行在各種品牌的手機上,但是各種品牌的手機在硬件上都會有差異,因此,很多廠商都會對源碼進行定制,以修改它的某些部分來配合自家硬件的特性,比如我有某個傳感器,別的廠商沒有,我的攝像頭比較特殊,運行起來比較復雜,這些都屬於硬件差異。由於我使用的Friendly-arm提供的源碼,所以我可以在這個目錄下看到一個friendly-arm的文件夾,里面是針對friendly-arm的開發板定制的一些代碼,等會兒我們會多次訪問這里。
還有一些等下我們會常用的目錄,比如system,external,out等等,這些我們等會兒用到的時候再說。
如何在源碼中添加自己的可執行文件
我們如果想要一個屬於自己的開機啟動進程,那首先就要一個我們自己編寫的程序了,一般來說,在實際項目中這個程序就是我們想要開機啟動的驅動,正如文章開頭所說的那樣,但是在我們這個例子中,我就不搞那么復雜了,寫一個最簡單的C語言程序,讓它作為我們的開機啟動進程。我給這個程序命名為loop,也就是循環的意思,代碼如下:
#include <stdio.h>
int main() {
int i = 0;
for(i;i<100;i++)
{
sleep(180);
printf("I am a process\n");
}
return 0;
}
怎么樣,是不是非常簡單,任何有任何語言編程基礎的人都能看懂:我們設置了一個循環,每次在執行循環體的內容前,將主線程休眠180秒,一共循環100次,而循環的內容就是輸出一條語句。
我為什么要這么做,主要是因為,如果這個程序一下子就執行完成,這個進程就死掉了,那我們就不能在命令行終端中看到這個進程,所以每次循環的時候我都會讓它休眠180秒,這樣算下來,這個進程理論上可以保活5小時,嗯,夠長了,手速再慢的人也能在5小時內用命令行終端登入開發板,然后輸入命令查看當前活動的進程了。
現在我們要把這個寫好的.c文件放到Android源碼目錄下,進入Android源碼目錄,找到vendor文件夾,然后新建一個自己的文件夾,我給它起名叫“while-process”,我們就把它放在這個里面。那么如何才能讓它和源碼一起編譯呢,這時就涉及到了一個知識點——Android.mk。
自定義Android.mk
這里簡單介紹下如何編譯Android源碼,等下還會詳細介紹。編譯Android源碼簡單來說,就是做一大堆准備工作,然后在命令行工具中使用make命令進行編譯,make命令會在源碼目錄中遍歷所有目錄,找到里面的Android.mk文件,然后根據Android.mk文件的內容編譯當前目錄下的代碼。所以說我們可以理解Android.mk配置文件是一個編譯指南。關於Android.mk文件所能擴展出來的知識點也是非常的多,這里我也只介紹一些我們最需要和最基本的東西。首先你需要隨便找一個Android.mk文件然后用記事本之類的軟件打開它。
首先,這行代碼必須有:“LOCAL_PATH:= $(call my-dir)”,這行表示所要編譯的內容在本Android.mk文件所在的目錄下。
然后,Android.mk文件中可以指定多個編譯模塊,每個編譯模塊都是以include $(CLEAR_VARS)
開始,以include $(BUILD_XXX)
結束。
然后在這兩代碼中間我們找到LOCAL_SRC_FILES:= \xxx
,后面的xxx就表示你要編譯的源文件,比如我剛才寫的程序叫loop,這里就寫loop.c;我們還會看到LOCAL_MODULE:= xxx
,這里表示編譯的模塊的名字,在這里我們把xxx換成loop。
由於我們這個程序非常簡單,所以更多的屬性在這里就不介紹了,感興趣的可以去下面這篇文章去查閱:http://blog.chinaunix.net/uid-25838286-id-3204120.html
你如果不知道怎么創建Android.mk文件,最簡單的方法就是隨便找一個Android.mk文件拷貝過來,然后刪掉些對你沒用的語句,增加些對你有用的語句,然后改改某些語句的值或者變量名,就可以用了,如果編譯失敗,就按照提示進行修改,多試幾次就可以了。
編譯Android源碼
由於講解了Android.mk,所以我這里就先講一下Android源碼的編譯,不過其實這是最后幾步才要做的事情,但是先編譯也是有好處的,因為第一次編譯的時候時間會非常的長,你可以一邊讓它編譯着,一邊了解下面的知識點。當你后面的工作全部完成以后再次編譯的時候,只要你不清空之前的編譯結果,它就會進行增量編譯,也就是只編譯修改過的地方,這樣只需要幾分鍾就能完成了。
Android源碼怎么在ubuntu下編譯,這個網上的文章有很多,我這里簡要的說明一下。如果你使用的是開發板,請找到開發板對應的官方文檔,然后嚴格按照文檔中的教程一步一步來一般不會遇到什么問題。比如說我用的開發板的文檔中給出的步驟大致如下:
1.搭建編譯環境。這里需要一堆支持包,你可以先不用管這些支持包是什么,按照如下命令安裝即可:
sudo apt-get install bison g++-multilib git gperf libxml2-utils make python-networkx zip
sudo apt-get install flex libncurses5-dev zlib1g-dev gawk minicom
2.使用命令行工具的cd命令進入Android源碼目錄,然后依次執行以下三個命令:
source build/envsetup.sh
lunch aosp_nanopi3-userdebug
make -j8
這三行命令第一行是設置編譯環境,第二行是選擇編譯方案,也就是我剛才所說的選擇廠商定制的方案,可以看到nanopi3是我的開發板的型號,所以就選擇這個方案,第三行是開始編譯,后面的-j8代表的是使用8線程同時編譯,使用幾個線程同時編譯要看你的電腦配置,一般來說和你電腦的處理器有關。例如你的電腦裝有四核處理器,每個核有兩個線程,那你就可以使用j8,也就是4*2。選對同時編譯的線程數量合適,編譯的速度就能成倍增長。如果你是第一次編譯源碼,最慢的話時間可能長達一晚上之久,如果你之前成功編譯過,那這次編譯就是增量編譯,系統只會編譯你修改過的地方,很人性化,只需要幾分鍾。
編譯過程中也許會遇到一些問題從而停止編譯,比如你無權操作某些文件等等,這些都會在命令行工具中有英文提示,看着提示改就行了,這里的提示的英文也不復雜。建議在執行命令前先進入root用戶,也就是先使用su命令。
編譯成功以后,我們先進入Android源碼目錄,然后進入以下這個目錄:out/target/product/nanopi3;還是那句話,根據你選擇的編譯方案,即你使用的開發板型號不同目錄會有區別。進入這個目錄下面以后我們能看到很多個img鏡像文件。
3.現在我們把我們編譯好的系統刷到我們的開發板上,在這之前先准備一張足夠大的SD卡,然后用讀卡器把SD卡連接到電腦上。
我使用的方式是使用刷機腳本來刷。首先執行以下兩條命令:
git clone https://github.com/friendlyarm/sd-fuse_s5p6818.git
cd sd-fuse_s5p6818
意思就是時候用git下載這個刷機工具,然后進入這個刷機工具的目錄。執行以下兩條命令:
su
./fusing.sh /dev/sdx
這兩條命令的意思是,首先進入root用戶,如果你剛才已經進入root用戶了,可以不用執行su這條命令,下面一行就是開始刷寫,其中sdx是你的sd卡的設備名,請把sdx換成你的設備名,比如我的sd卡叫做sdb,就把sdx換成sdb。
刷寫成功后,我們把卡插入開發板,然后用USB線把開發板和電腦連接,然后執行命令:
adb remount
adb shell
這時我們就已經使用命令行工具登入到開發板了,現在我們要找到我們寫的loop程序。比如我把它放在了system/bin目錄下,使用cd命令進入這個目錄,然后使用ls命令就可以看到它存在,如果想要執行它,就使用./命令,loop這個程序就執行了,執行以后我們能看到每三分鍾就可以在命令行終端中看到它輸出一行語句,但是我們需要確保這個loop這個進程確實存在,那我們就需要用ps -Z命令查看它,但是當前這個命令行工具窗口正在運行程序,無法使用命令,所以我們就新建一個命令行終端窗口,像剛才一樣使用adb shell命令登入開發板,然后使用命令ps -Z。就能看到它正在運行了。
編譯Android源碼這一塊不是我們本講的重點,這一塊沒有什么概念需要理解,就是一些操作步驟的流水賬,我寫的比較簡單,中間難免有疏漏會造成一些小問題,如果讀者出現了問題,可以根據具體問題去網上搜索或者給我留言,網上關於如何編譯Android源碼如何編譯的文章是非常多的,不過我還是建議你參照你使用的開發板的官方文檔,嚴格按照上面的步驟一步一步來,這樣發生不必要的問題的概率會小一些。
init.rc介紹
我先來做個名詞解釋,什么是init.rc,那就要從什么是init說起。init是由Android的Linux內核啟動的第一個第一個進程,這個進程非常特殊,它的PID永遠是1,並且這個進程是不會死亡的,如果它死亡,內核就會崩潰。init進程啟動后會fork出很多及其重要的系統進程,比如我們做應用開發的時候都耳熟能詳的zygote進程,我們所有的應用程序的進程都由zygote拉起。解釋完了init進程,我們再說init.rc,init.rc是一個規定init進程行為和動作的配置文件。init進程可以做哪些事情,都由它規定。關於init.rc的詳細介紹,大家可以參考這篇文章:
我們這里只對init.rc做一個簡單的介紹,init.rc文件中只包含兩種聲明,on和service,我們可以把on稱為行為,把service稱為服務(這里的服務和應用開發中四大組件中的服務以及通過context.getSystemService()所得到的系統服務都不是一個東西,我一直不知道該怎么給它起名,姑且叫它init服務)。service聲明了服務以及服務的各種行為。我們標題中說的開機啟動進程就是這里的init服務。service只定義服務,但不能讓服務做任何事情,如果你需要服務能夠產生啟動或者停止等相關動作,你就需要on,每個on下面的有各種命令,其中就包括很多對init服務的操作。這里要提到的是,我們要修改的init.rc文件在device/friendly-arm/nanopi3目錄下,也就是廠商定制的版本,如果你使用的是別的開發板,可以去相應的目錄找找。我們來看看init.rc中on和service兩個典型的定義:
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0
# Set the security context for the init process.
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
# Set the security context of /adb_keys if present.
restorecon /adb_keys
start ueventd
# create mountpoints
mkdir /mnt 0775 root system
......
......
......
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
#
后面的一行是注釋。
現在我們只重點關注幾行,我們看到on下面有一行是“start ueventd”,而下面service的名字也是ueventd,這表明什么,我想大家都猜到了,那就是在early-init這個on啟動了ueventd這個service。對,on就是這樣啟動sercice的,當然,on還有例如restart以及stop等等其它對service的操作,分別是讓service停止並重新啟動以及停止,不過on並不只是為service而生的,它還有許多其它的命令,在這里我就不詳細介紹了,大家可以去網上搜索相關文章或者看這本書《構建嵌入式Android系統》。
我們看完了on再看看service,service我也只是簡單介紹一下,service關鍵字聲明了你要定義一個service,而ueventd就是這個service的名字,至於后面的目錄則是這個service對應的可執行文件在系統中的位置。
注意:這里是說在系統中的位置,也就是在開發板運行你的Android源碼編譯的系統后的目錄,而不是源碼的目錄,至於Android源碼的編譯,等下再講。
接下來,我們可以看到service下面也有很多東西,這里我們不叫它們命令了,叫屬性或者參數也許會比較好,其中比較重要的是class core,表示這個service屬於core這個class,class我們不需要深入去管它,只要把它理解成一組service的集合就行,至於后面的屬性,等下我們開始配置service的時候再說。
在init.rc中配置service
我們先來理一理,我們現在通過上文的講解已經得到了什么。我們已經編寫了一個自己的C語言程序loop,並且把它放在了Android的源碼中,Android的源碼也編譯好了,如何把編譯好的Android系統刷到開發板上並啟動我們也已經學會了。
但是最重要的目的還沒實現,那就是讓loop這個可執行文件開機就可以被啟動。而現在我們正要做的就是這件事。
首先打開Android源碼目錄,進入device/friendly-arm/nanopi3文件夾下,然后打開inti.rc文件,我們正式開始配置。
首先定義一個service,還記得service是怎么定義的嗎,我這里定義的語句如下:service qya system/bin/loop。相信不難理解吧,我們定義了一個服務叫qya,它對應的程序是system/bin目錄下的loop。這些上面都講了。然后我在這個service下面增加幾個配置屬性:
service qya /system/bin/loop
class main
console
oneshot
其中console表示服務需要並運行在控制台,oneshot表示服務只運行一次,在退出時將服務設置為禁用。
你可以根據你的需要來增加這些屬性,我寫的兩個屬性並不一定都是必須的。《構建嵌入式Android系統》這本書的第六章對這些屬性參數介紹的非常詳細,如果網上找不到相應的文章可以拿這本書看看。
也許有人會發現,class main這是個什么東西,好像沒講,然而我並不是忘了,我在這里再詳細講講。我之前講過start命令是在on中啟動serice,但是通覽整個init.rc文件,我們會發現,直接使用start命令啟動service的情況非常少,我之前也用這種方式試過幾次,但都未能成功。所以我在仔細閱讀和查詢資料后發現,大多數inti進程fork出來的開機啟動進程都是用另外一種方式來啟動。我們來看看下面一個on行為的定義:
on property:vold.decrypt=trigger_restart_min_framework
class_start main
我在這里再簡單說一下on,on分為兩種,第一種一共有7個,它們是一定會隨inti進程的啟動而執行的,比如我們上面介紹init.rc的時候展示的early-init正是這7個on中的第一個。而第二種on則是在滿足某些特定條件時才會啟動的,比如我們這里的這個on就是第二種。我們看到它下面有一條class_start main命令,而我們的service下面第一個屬性正是class main。所以可以理解了,這個class_start main命令是啟動main下面所有service。通覽init.rc文件,我們會發現屬於main的service非常多,所以我們的service也就搭一趟便車,擠上main的隊伍。
SELinux/SEAndroid
看起來我們最后一步已經做了,把我們的loop程序成功添加到init.rc的文件中。還沒完,我們將會面臨本文從開頭到現在為止最大的挑戰。我們的進程會被SEAndroid這個東西禁止掉,從而你無論怎么ps -Z
你也不會看到它的存在。那么,SEAndroid到底是個什么東西?如果你想深入研究它,那可得好好花上一段時日了,我在這里給出兩位大神的系列文章,專門分析什么是SEAndroid。這兩位大神分別是羅升陽前輩和阿拉神農前輩,兩人講解SEAndroid的文章地址如下:
http://blog.csdn.net/luoshengyang/article/details/35392905
http://blog.csdn.net/innost/article/details/19299937/
其中,羅升陽老師的文章比較長,分析的比較理論,有助於你全面而細致的了解SEAndroid。而阿拉神農的文章則更加實用,讓你快速能看懂這個東西,但是理論上並沒有羅老師的深,大家可以各取所需。
我在這里越俎代庖的稍微講一下什么是SEAndroid。老習慣,一句話:Android的系統安全機制。它來源於Linux系統中的SELinux。關於它們的歷史我這里也都不講了,總之SEAndroid是這樣管理權限的:凡是任何想要運行的進程,想要做任何事情,都必須在安全策略配置文件中賦予權限,如果沒有聲明某個權限,那它就沒有這個權限。
要理解其實很容易,做應用開發的時候,我們常常需要在AndroidManifest.xml文件中賦予應用權限。
比如,如果你的應用想要讀寫磁盤數據,那你就要寫permission語句,賦予它讀寫磁盤的語句,如果你的應用想要訪問網絡,那你就需要寫一條關於網絡的permission語句,以准許它訪問網絡。SEAndroid也是類似的東西,你的進程想要干什么,你就得給它寫一個.te文件,然后在文件中使用allow語句賦予它權限,不同的是SEAndroid的安全策略文件.te比AndroidManifest.xml可是難寫多了。
我這里對編寫.te文件和上面Android.mk一樣,不做深入介紹。想詳細了解如何編寫.te文件,就去參考阿拉神農前輩的文章。我這里只做一個簡單的介紹。
我們隨便來找一條.te文件中的allow語句:allow netd proc:file write。這條語句是阿拉神農的文章中給出的示例,他在文章詳細分析了這條語句每個詞是干什么的,但我在這里也不多說,還是老慣例,一句話:允許netd進程對proc type的file進行寫(write)操作。
我們這里把這條語句換一下:寫成:allow a b:c d。那意思就是允許a進程,對c這個b類型的objec class進行d操作。不過這里的類型(type)是SEAndroid中的概念,很難三言兩語說清楚,所以請看上面的文章,而file也不是我們通常理解的文件,而是一種object class,表示一種可以被操作的對象,比如,除了file以外還有Dir,Socket等等,由系統規定,這里也不展開了。
到這里我再廢話兩句,SEAndroid把操作系統中的東西分為兩種,能發起動作的進程,以及只能被進程操作的文件,而allow語句則就是規定允許誰對誰做什么的。其實SEAndroid的知識遠不止這些,還有例如MLS分級系統等等,不過這里就不討論了,再提示一下,想深入了解的,看上面兩篇文章吧!
好的,現在我們要開始真正動手了。首先進入Android源碼目錄,然后進入:external/sepolicy。還是和上面一樣,我也不知道怎么創建一個.te文件,我們直接隨便找個.te文件,不過說是隨便,我們不能真的隨便,我們也要想一想,怎么做成功率高,記得我說過我們自定義的service是屬於main這個class的吧,那我們就找一個同樣在main這個class下面的其他服務的.te文件來修改,因為在同一個class中的進程,所需的權限應該是相近的。
好,我們找到一個,然后把它的名字改成loop.te。注意啊,我們的service的名字叫qya,但是我們要執行的程序叫loop,SEAndroid是賦予進程權限而不是賦予service權限,所以我們的.te名字叫loop.te而不是qya.te。.te文件中除了allow語句以外還有一些其它語句,比如type等等,它們是什么意思,大家就自己去查一查吧,
我這里給出大家一個投機取巧的辦法,如果你不想現在了解SEAndroid,那我就教你一個辦法,比如我的.te文件是復制uncrypt的,那進到這個文件里面以后,就把文件中所有寫uncrypt的地方全部改成loop,一般來說就可以了。如果編譯的時候不通過,你就仔細看錯誤提示,我當時不通過的原因是有兩行allow語句和domain.te文件中的neverallow語句相沖突,看字面意思也能明白,neverallow的意思是從不允許,如果這里允許了一件事情,那里又不允許這件事情,勢必發生沖突,那我們只需要把我們的.te文件中的相關allow語句注釋掉或者刪掉就行了。
測試
現在我們該修改的東西終於全部改完了,那我們要做的就是重新編譯,怎么編譯上面已經介紹過了,由於這次只是增量編譯,所以只需幾分鍾就OK,我們把它刷到開發板上,然后給開發板插上USB線和電腦連接,然后在命令行工具中執行兩條命令:
adb remount
adb shell
現在我們的命令行工具已經登入到開發板上了,直接使用命令ps -Z,我們就能在窗口中看到我們的進程正在后台運行了,我們沒有用./命令去執行loop,所以它就是被init進程fork出來的。命令行窗口的截圖如下所示:
我們可以看到最下面的我們最熟悉的進程zygote,它的上面就是我們自定義的loop進程,自此,自定義int.rc開機啟動service成功,我們大功告成。
總結
理一理本文所涉及到的知識點,有:編譯Android源碼,Android.mk文件的編寫,修改Android源碼,init.rc介紹,SEAndroid。
每個知識點都是為了我們能成功運行自定義service而講解,所以講解的深度其實都是不夠的,我在文中不少地方都已經貼出了詳細介紹每個知識點的博文的地址供大家后續學習。加上本文篇幅也算比較長的了,加上介紹的知識又多又雜,難免有疏漏之處,如果你按照本文的方法在配置過程中出現了失敗的地方,可以根據具體問題上網搜索,只要堅持,一定可以解決。
Android底層的知識的特點就是多而雜,所以做底層開發最需要的就是耐心,祝所有走在底層開發的小伙伴都能學習順利。