一、如何設(shè)置開機啟動某個程序?
1.需求描述
最近有個項目需要在Android開機啟動之后,自動執(zhí)行一個C語言編寫的程序:pengd
該程序運行時需要修改網(wǎng)絡(luò)ip地址及其他網(wǎng)絡(luò)操作,所以需要root權(quán)限
根據(jù)需求描述,我們需要做一下操作:
將pengd 預(yù)置到Android中的某個路徑下,比如放在 /sbin/pengd
;
然后修改init.rc
文件,實現(xiàn)開機后自動運行我們的程序pengd
本次項目用到的安卓設(shè)備的init.rc和sbin下的文件重啟后會恢復(fù)默認,主要是安卓部分目錄是基于ramdisk,因此我們需要重新制作ramdisk.img
,將前面2個步驟的操作同步到到ramdisk.img
,然后再重新燒錄設(shè)備對應(yīng)分區(qū)
2.移植步驟
1)解壓縮ramdisk.img
假定廠家提供文件名為:ramdisk_new
peng@ubuntu:~/work/ramdisk$?mv?ramdisk_new.img?ramdisk_new.img.gz
peng@ubuntu:~/work/ramdisk$?gunzip?ramdisk_new.img.gz?
peng@ubuntu:~/work/ramdisk$?cpio?-i?-F?ramdisk_new.img?
5385?blocks
2)修改init.rc、
修改init.rc文件,如下:
service?pengd?/sbin/pengd
????seclabel?u:r:pengd:s0
????user?root
????group?root
????disable
????oneshot
on?property:sys.boot_completed=1
????start?pengd
????
注意rc文件最后一定要有空行,否則編譯報錯!
“
init.rc語法見第二章
該配置文件并不是唯一寫法,具體要參考實際廠家提供的sdk中的ramdisk”
3) 拷貝程序pengd
直接拷貝pengd到
?/home/peng/work/ramdisk/sbin
也可以是其他bin目錄
4)重新壓縮ramdisk
peng@ubuntu:~/work/ramdisk$?rm?ramdisk_new.img??第一次
peng@ubuntu:~/work/ramdisk$?find?.?|?cpio?-o?-H?newc?>?../ramdisk.img.unzip
peng@ubuntu:~/work/ramdisk$?cd?..
peng@ubuntu:~/work$?gzip?-c?./ramdisk.img.unzip?>?./ramdisk.img.gz
peng@ubuntu:~/work$?mv?ramdisk.img.gz?ramdisk_new.img
peng@ubuntu:~/work$?chmod?766?ramdisk_new.img
3. 運行測試
采用廠家提供的燒錄工具燒錄ramdisk即可,不在截圖。
可以adb shell登錄安卓設(shè)備,用以下命令查看進程是否生效:
ps?-ef?|?grep?pengd
二、init.rc詳解
0、 什么是init.rc?
1)init.rc基礎(chǔ)概念
Adnroid系統(tǒng)就像是是運行在linux系統(tǒng)上的一個“服務(wù)進程”,并不算是一個完整的操作系統(tǒng)。
這些服務(wù)進程是維持設(shè)備正常運轉(zhuǎn)的關(guān)鍵,而這些進程的鼻祖就是init進程。
進程ID為1,源代碼位于system/core/init 目錄。
作為Android系統(tǒng)的第一個進程,Init進程承擔(dān)這很多重要的初始化任務(wù),一般Init進程的初始化可以分為兩部分,前半部分掛載文件系統(tǒng),初始化屬性系統(tǒng)和Klog, selinux的初始化等,后半部分重要通過解析init.rc來初始化系統(tǒng)daemon服務(wù)進程,然后以epoll的監(jiān)控屬性文件,系統(tǒng)信號等。
init.rc則是init進程啟動的配置腳本,這個腳本是用一種叫Android Init Language(Android初始化語言)的語言寫的。
2) init.rc語法
init.rc語法官方文檔路徑:system/core/init/Readme.txt
下圖是瑞芯微sdk的改文件路徑:
一個完整的init.rc腳本由4種類型的聲明組成:
- Action(動作)Commands(命令)Services(服務(wù))Options(選項)
on?<trigger>?[&&?<trigger>]*
???<command>
???<command>
???<command>
service?<name>?<pathname>?[?<argument>?]*
???<option>
???<option>
???...
3)語法規(guī)則:
- 注釋以 # 開頭關(guān)鍵字和參數(shù)以空格分隔,每個語句以行為單位C語言風(fēng)格的 轉(zhuǎn)義字符可以用來為參數(shù)添加風(fēng)格字符串使用 “ ”行尾的 用來表示和下面一行是同一行Actions(動作)和Services(服務(wù))就是一個新語句的開始,這個兩個后面跟著Commands(命令)或Options(選項)都屬于這個新語句Actions(動作)和Services(服務(wù))有唯一的名字,如果出現(xiàn)重名就會被當成錯誤忽略掉
1、Actions(動作)
一個動作其實就是響應(yīng)某個事件的過程。
如下圖所示:當early-init這個觸發(fā)條件產(chǎn)生時,依次執(zhí)行下面的命令1、命令2、命令3、命令4
【改文件位于system/core/rootdir/init.rc
】
源碼實現(xiàn)思想:
當相應(yīng)的事件發(fā)生后,系統(tǒng)就會對init.rc中的各個觸發(fā)條件進行匹配,只要匹配成功就會把這個動作加到“命令執(zhí)行隊列的尾部”,等待執(zhí)行。如果已經(jīng)存在是不會再次添加的。
2、Commands(命令)
命令會在條件觸發(fā)后一條一條的執(zhí)行。
1.)init.rc中常見的觸發(fā)條件:
觸發(fā)條件 | 解釋 | 示例 |
---|---|---|
boot | 這是init程序啟動后觸發(fā)的第一個事件 | on boot |
<name> = <Value> |
當屬性name滿足特定的value時觸發(fā) | on property:vold.decrypt=trigger_load_persist_props |
device-added-<path> device-removed-<path> |
當設(shè)備節(jié)點添加/刪除時會觸發(fā) | |
service-exited-<name> |
當指定的服務(wù)<name> 存在時觸發(fā) |
2)init.rc中常見的命令
init.rc中常見的Commands有以下一些:
exec <path> [ <argument> ]
創(chuàng)建和執(zhí)行程序(<path>
). 這將會阻塞init,直到程序執(zhí)行完成。由于它不是內(nèi)置命令,應(yīng)盡量避免使用exec,它可能會引起init卡死。
export <name> <value>
在全局環(huán)境變量中設(shè)在環(huán)境變量<name>
為<value>
。(這將會被所有在這命令之后運行的進程所繼承)
ifup <interface>
啟動網(wǎng)絡(luò)接口<interface>
import <filename>
解析一個init配置文件,擴展當前配置。
hostname <name>
設(shè)置主機名。
chdir<directory>
改變工作目錄。
chmod <octal-mode> <path>
更改文件訪問權(quán)限。
chown <owner> <group> <path>
更改文件的所有者和組。
chroot <directory>
改變進程的根目錄。
class_start <serviceclass>
啟動該類service所有尚未運行的服務(wù)。
class_stop <serviceclass>
停止所有該類正在運行的service。
domainname <name>
設(shè)置域名。
enable <servicename>
改變一個disable的service為enabled。一般用于service在init.rc中被標記為disabled,這樣的service是不會被啟動的,當滿足一定的觸發(fā)條件時,可以同enable命令來將他變?yōu)閑nabled。示例:
??on?property:boot_completed=1
??enable?my_service_name
insmod <path>
安裝位于<path>
的模塊(PS:驅(qū)動)。
mkdir <path> [mode] [owner] [group]
在<path>
創(chuàng)建一個目錄,(可選)使用給定的模式,所有者個組。如果沒有提供,該目錄將用755權(quán)限,所有者為root用戶,組為root。
mount <type> <device> <dir>[ <mountoption> ]*
嘗試掛載<device>
到<dir>
,<device>
可能有mtd@name形式,以指定名為name的mtd塊設(shè)備。
<mountoption>
包括 "ro", "rw", "remount", "noatime", ...restorecon <path> [ <path> ]*
恢復(fù)名為<path>
的文件在file_contexts中配置的的安全級別。自動被init標記正確,不需要用init.rc創(chuàng)建的目錄。
restorecon_recursive <path> [ <path> ]*
遞歸的恢復(fù)<path>
指出的目錄樹中file_contexts配置指定的安全級別。path不要用shell可寫或app可寫的目錄,如/data/locla/temp,/data/data,或者有類似前綴的(目錄)。
setcon <securitycontext>
設(shè)置當前進程的security context為特定的字符串。這是典型的僅用于所有進程啟動之前的early-init設(shè)置init context
setenforce 0|1
設(shè)置SELinux系統(tǒng)范圍的enfoucing狀態(tài)。0 is permissive (i.e. log but do not deny), 1 is enforcing.
setprop <name> <value>
設(shè)置系統(tǒng)屬性<name>
為<value>
.
setrlimit <resource> <cur> <max>
為特定資源設(shè)置rlimit
setsebool <name> <value>
設(shè)置SELinux的bool類型<name>
為<value>
。<value>
may be 1|true|on or 0|false|off
start <service>
啟動一個服務(wù)(如果服務(wù)尚未啟動)。
stop <service>
停止服務(wù)(如果正在運行)。
symlink <target> <path>
創(chuàng)建一個符號連接,at <path> with the value <target>
。
sysclktz <mins_west_of_gmt>
Set the system clock base (0 if system clock ticks in GMT)
trigger <event>觸發(fā)一個事件。一個動作將另一動作排隊。
wait <path> [ <timeout> ]
poll特定的<path>
,出現(xiàn)后返回,或timeout到達。如果timeout沒有指定,默認為5秒。
write <path> <string>
打開一個位于<path>
的文件,寫入(不是追加)字符串<string>
。
3、Services(服務(wù))
Services其實是可執(zhí)行程序,他們在特定選項的約束下會被init程序運行或者重啟。
一般格式:
Service?<name>?<pathname>?<argument>
?<option>
?<option>
......
其中標識符含義如下:
?<name>表示service的名稱
?<pathname>表示service所在的路徑
?<argument>表示啟動service所帶的參數(shù)
?<option>表示對這個service的約束選項
4、Option選項
Option用來定義Service的行為,決定了Service將在何時啟動,如何運行等。常用的Option有包括以下一些。
critical
-
- 這是十分關(guān)鍵的服務(wù)。如果在四分鐘內(nèi)退出超過四次,手機將會重啟并進入recovery模式。
disabled
-
- 這種類型的服務(wù)不會自動啟動。它必須明確的使用名字啟動。
setenv <name> <value>
-
- 設(shè)置環(huán)境變量=在加載的進程中。
socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
-
- 創(chuàng)建一個名為
/dev/socket/<name>
- 的UNIX域socket并將fd傳遞到加載的進程中。
<type>必須是"dgram",?"stream",?"seqpacket"中的一種。
<user>和<group>默認為0.
<context>是?SELinux?socket?安全上下文,默認為service安全級別,
可以指定為seclabel或根據(jù)service的可執(zhí)行文件的安全級別計算。
user <username>
-
- 在執(zhí)行該service前改變用戶名,默認為root。如果你的進程請求Linux的特殊能力,就不要用這個命令。需以進入進程仍是root->請求特權(quán)->切換到你期望的uid來替換此法。
group <groupname> [ <groupname> ]*
-
- 在執(zhí)行該service前改變組名。第一個以后的附加組名用于設(shè)定進程的附加組(通過setgroups())。當前默認是root。
seclabel <securitycontext>
-
- 在執(zhí)行服務(wù)之前改變安全級別。主要用于從rootfs執(zhí)行服務(wù),比如ueventd, adbd. 在system分區(qū)上可以用基于文件安全級別的策略定義的transition,如果沒有指定且沒有定義策略的transition,默認是init上下文。
oneshot
-
- 退出不重啟服務(wù)(名副其實,一次性)。
class <name>
-
- 為一service指定一個類名,所有有相同類名的service可以一同啟動或停止。如果沒有用class選項指定類名,該service屬于"default"。
onrestart
- 在service重啟的時候執(zhí)行。
這是一口君的新書,感謝大家支持!