概述
在前段時間的作業中,需要開發一個開機自動啟動的腳本,現把開發程序記錄一下
主要框架
撰寫一個可以開機自動啟動的腳本,方法就是通過rc檔案,在boot_complete=1時,去啟動這個服務,那么,可以先基于以上思路,創建實作腳本所需要的檔案,
通常來說,我這個腳本是要放在vendor磁區的,因此將腳本放到vendor目錄下,參考其他的腳本,創建3個空的檔案如下:
multi_tpinsmod/ //腳本檔案夾
├── Android.bp //bp檔案,用于放置編譯引數
├── multi_tpinsmod.cpp //腳本的代碼實作
└── multi_tpinsmod.rc //rc檔案,用于啟動腳本
0 directories, 3 files
接下來,我們就來實作如上框架,
腳本撰寫
腳本的實作方式有很多,包括c/c++,shell等,基于簡單高效的原則,shell是比較好的選擇,但是對于Android的開機自啟動腳本,個人建議是選擇c/c++來撰寫,如果是用于除錯的手動執行腳本,可以使用shell來寫,主要原因如下:
- Android中有許多權限問題,而以shell腳本來說,會有許多的selinux權限限制(并且許多權限還無法繞過),如果是開機自啟動的腳本來說,我們并沒有adb那樣的權限,因此很容易導致運行失敗,
- 手動執行腳本,我們可以通過su和setenforce 0來臨時獲取權限,且shell腳本易于修改,
由于本次是需要進行開機啟動的,那么這里筆者選擇使用了c++來實作腳本,代碼主體不多贅述,依個人實作,
Android.bp
腳本的主要代碼撰寫好后,Android.bp的內容如下:
cc_binary { //表示將腳本編譯為bin檔案
name: "multi_tpinsmod", //模塊名字
init_rc: ["multi_tpinsmod.rc"], //模塊關聯的rc檔案
relative_install_path: "hw", //是否放在hw路徑下
vendor:true, //表示編譯到vendor磁區
cflags: [ //flag,用于忽略一下warning
"-Wall",
"-Wextra",
"-Werror",
],
shared_libs: [ //需要使用的共享庫
"libbase",
"liblog",
"libprocessgroup",
"libcutils",
"libutils",
],
srcs: [ //源檔案
"multi_tpinsmod.cpp",
],
}
rc撰寫
rc檔案的撰寫則比較簡單了,參考如下
on property:sys.boot_completed=1 //在開機啟動完成時的動作,這里是啟動服務
start multi_tpinsmod
service multi_tpinsmod /vendor/bin/hw/multi_tpinsmod //定義了一個服務,和該服務的執行檔案路徑
disabled //表示不隨class自動啟動,需要手動啟動
user root //用戶
group shell root //分屬的用戶組
oneshot //表示服務退出后不重新啟動
capabilities SYS_MODULE
rc檔案的參考如上,其余rc,可以參考網上資料自行學習,
編譯
以上代碼都準備好了以后,就可以進行編譯了,編譯可以通過mm命令直接在原始碼路徑下執行,也可以將其配置到方案里面編譯整個sdk,
一. 除錯可以在原始碼目錄下通過mm編譯,執行mm需要先在top目錄執行過lunch等
二.在sdk里面編譯的方法如下:
- 在方案目錄,找一個地方,增加PACKAGE_PRODUCT +=,參考如下
#support multi_tpinsmod
PRODUCT_PACKAGES += \
multi_tpinsmod
-
編譯整個sdk,如果有編譯錯誤,自行解決
-
編譯完成后,在out目錄下,搜索是否有編譯出來的產物,如rc檔案和bin檔案
除錯
編譯完成后,燒錄韌體到機器中,然后可以通過手動執行的方式,查看腳本功能是否實作,
如果有權限報錯,可以先臨時關閉selinux進行除錯,臨時關閉selinux方式如下:
在adb中執行
setenforce 0
臨時關閉selinux權限,然后手動執行腳本,確保腳本功能完成,腳本功能完成后,就可以進行腳本的權限除錯了,
權限設定
更改檔案的權限型別
一般來說,檔案的型別在vendor目錄下,是vendor_file,這種型別是沒有執行權限,也就是無法通過rc來啟動的,查看檔案型別可以通過ls -lZ命令查看:

如圖所示,通過ls -lZ查看檔案的型別,如果看到型別為vendor_file,則表示需要組態檔的型別,以獲取執行權限,
修改步驟如下:
- 找到配置selinux權限位置,一般來說,可以通過在Android目錄下執行如下命令來獲取selinux的配置目錄,
get_build_var BOARD_SEPOLICY_DIRS
- 找到目錄后,如筆者的配置位置在
device/softwinner/common/sepolicy/vendor
- 在目錄下,先新建一個與腳本名字相同的te檔案,如筆者的腳本名為A,那么可以新建一個檔案A_default.te的檔案
- 在新建的te檔案中,撰寫如下:

表示新建一個名字為multi_tpinsmod的domian域
- 在同目錄下的file_contexts中,增加如下

其中,前面為bin檔案的路徑,后面為韌體格式,中間的為剛才新建的multi_tpinsmod_defalut.te中的執行型別,
- 完成后,重新編譯韌體,燒錄韌體,再次查看bin檔案的型別,查看型別是否已經從vendor_file變成了自己所定義的multi_tpinsmod_exec型別,
- 臨時關閉selinux權限,然后手動執行bin檔案,查看串口(或者dmesg),查看是否有類似的報錯資訊
type=1400 audit(1629099780.612:406): avc: denied { write } for comm="tp_module_insmo" name="property_service" dev="tmpfs" ino=11726 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:property_socket:s0 tclass=sock_file permissive=1
type=1400 audit(1629099780.612:407): avc: denied { connectto } for comm="tp_module_insmo" path="/dev/socket/property_service" scontext=u:r:tp_module_insmod:s0 tcontext=u:r:init:s0 tclass=unix_stream_socket permissive=1
type=1107 audit(1629099780.616:408): uid=0 auid=4294967295 ses=4294967295 subj=u:r:init:s0 msg='avc: denied { set } for property=persist.vendor.tp.name pid=1056 uid=0 gid=2000 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:vendor_default_prop:s0 tclass=property_service permissive=1'
type=1400 audit(1629099780.632:409): avc: denied { sys_module } for comm="tp_module_insmo" capability=16 scontext=u:r:tp_module_insmod:s0 tcontext=u:r:tp_module_insmod:s0 tclass=capability permissive=1
type=1400 audit(1629099780.632:410): avc: denied { module_load } for comm="tp_module_insmo" path="/vendor_dlkm/lib/modules/gslX680new.ko" dev="overlay" ino=48232 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:vendor_file:s0 tclass=system permissive=1
type=1400 audit(1629099780.832:411): avc: denied { read } for comm="tp_module_insmo" name="input" dev="sysfs" ino=8803 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:sysfs:s0 tclass=dir permissive=1
tp_module_insmo (1056) used greatest stack depth: 9936 bytes left
type=1400 audit(1629099780.840:412): avc: denied { open } for comm="tp_module_insmo" path="/sys/class/input" dev="sysfs" ino=8803 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:sysfs:s0 tclass=dir permissive=1
type=1400 audit(1629099780.840:413): avc: denied { read } for comm="tp_module_insmo" name="name" dev="sysfs" ino=39538 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
type=1400 audit(1629099780.840:414): avc: denied { open } for comm="tp_module_insmo" path="/sys/devices/platform/soc@2900000/5002000.twi/i2c-0/0-0040/input/input7/name" dev="sysfs" ino=39538 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
說明腳本已經基本完成,只剩余selinux權限問題,下一步就是配置權限問題,
配置selinux權限
手動配置權限
回到我們剛才創建的multi_tpinsmod_defalut.te,權限的配置則需要在該檔案來完成,
決議selinux資訊
我們拿一條selinux權限來看,例如:
type=1400 audit(1629099780.832:411): avc: denied { read } for comm="tp_module_insmo" name="input" dev="sysfs" ino=8803 scontext=u:r:tp_module_insmod:s0 tcontext=u:object_r:sysfs:s0 tclass=dir permissive=1
那么該陳述句表示需要配置的權限如下:
- scontext:誰需要權限,這里表示為tp_module_insmod
- tcontext:需要的是誰的權限,這里表示需要獲取sysfs的權限
- tclass:需要獲取的tcontext中表示的具體的類別,這里為idr
- avc: denied { read }:表示需要獲取的是read權限
那么組合起來就是:tp_module_insmod需要獲取sysfs中dir的read權限,那么,權限配置陳述句則為如下:
allow tp_module_insmod sysfs:dir read
以上陳述句就表示運行tp_module_insmod去讀sysfs中的檔案夾權限,
其他的可以自行完成,
使用audit2allow來快速配置權限
除了通過手動的方式配置權限,也可以通過使用在Android原始碼中的audit2allow工具來快速完成權限的配置,工具的使用步驟如下:
- 將所有相關的selinux的報錯復制到一個文本中,此操作最好在selinux關閉的情況下,去完成收集,這樣收集的比較全面
- 將log中的時間列印去除,陳述句以type=1400開頭,
- 將selinux報錯檔案放在android的top目錄中,然后執行audit2allow -i a.txt,執行結果如下:

可以看到,selinux陳述句被決議了出來,將其復制到對應的te檔案下,重新編譯,看是否會有報錯(audit2allow僅進行決議,部分權限是無法獲取的),
- 重新編譯,可能會有如下報錯提示:nerverallow···

可以看到,編譯提示,不允許vendor去獲取屬性的設定權限,這時可以先將報錯的陳述句給注釋掉,驗證其他的權限是否還存在問題,
nerverallow處理
一般來說,出現了nerverallow是比較頭疼的事情,出現的原因主要是使用了google不允許的權限導致的,那么解決辦法一般有2個:
- 在出現報錯的地方,強行注釋掉google不允許的權限,這樣可能會造成google的gms測驗無法通過
- 通過其他辦法繞過該權限,如vendor訪問system是沒辦法實作的,那就可以將需要訪問的資源再編譯一份放到vendor
prop的設定
在上面出現的vendor_default_prop是可以通過其他辦法進行繞過的,一般來說google不允許一個服務區獲取所有的vendor的屬性設定權限,但是允許獲取特定的屬性組的權限,以上述的屬性設定為例,設定方法如下:
- 獲取具體需要進行設定的屬性:需要在代碼中查看:
persist.vendor.tp.name
persist.vendor.tp.path
可以找到是對這2個屬性進行了設定和讀取,
- 在te檔案的目錄下,存在一個property.te檔案,在此處創建一個屬性型別
+type vendor_tp_prop, property_type, vendor_property_type;
- 在property_contexts中,將具體的2個屬性給到我們創建的vendor_tp_prop,參考如下

- 在我們自己的te檔案中,賦予屬性權限,陳述句如下:
set_prop(multi_tpinsmod, vendor_tp_prop)
- 實作后,再次編譯,沒問題,通過,
selinux注意事項
- 不要跨磁區呼叫,如system呼叫vendor里的檔案
- 部分無法執行的方法可以通過屬性的方式讓更高權限的init來執行:如在服務里設定某個屬性,然后由init在init.rc中觸發相應的動作,以此來繞過權限的限制
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/295446.html
標籤:其他
上一篇:常規應用系統無法抓包解決辦法整理
