在前段时间的工作中,需要开发一个开机自动启动的脚本,现把开发过程记录一下
编写一个可以开机自动启动的脚本,方法就是通过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来写,主要原因如下:
由于本次是需要进行开机启动的,那么这里笔者选择使用了c++来实现脚本,代码主体不多赘述,依个人实现。
脚本的主要代码编写好后,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文件的编写则比较简单了,参考如下
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里面编译的方法如下:
#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,则表示需要配置文件的类型,以获取执行权限。
修改步骤如下:
get_build_var BOARD_SEPOLICY_DIRS
device/softwinner/common/sepolicy/vendor
表示新建一个名字为multi_tpinsmod的domian域
其中,前面为bin文件的路径,后面为固件格式,中间的为刚才新建的multi_tpinsmod_defalut.te中的执行类型。
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权限问题,下一步就是配置权限问题。
回到我们刚才创建的multi_tpinsmod_defalut.te,权限的配置则需要在该文件来完成。
我们拿一条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
那么该语句表示需要配置的权限如下:
那么组合起来就是:tp_module_insmod需要获取sysfs中dir的read权限,那么,权限配置语句则为如下:
allow tp_module_insmod sysfs:dir read
以上语句就表示运行tp_module_insmod去读sysfs中的文件夹权限。
其他的可以自行完成。
除了通过手动的方式配置权限,也可以通过使用在Android源码中的audit2allow工具来快速完成权限的配置。工具的使用步骤如下:
可以看到,selinux语句被解析了出来,将其复制到对应的te文件下,重新编译,看是否会有报错(audit2allow仅进行解析,部分权限是无法获取的)。
可以看到,编译提示,不允许vendor去获取属性的设置权限,这时可以先将报错的语句给注释掉,验证其他的权限是否还存在问题。
一般来说,出现了nerverallow是比较头疼的事情,出现的原因主要是使用了google不允许的权限导致的,那么解决办法一般有2个:
在上面出现的vendor_default_prop是可以通过其他办法进行绕过的,一般来说google不允许一个服务区获取所有的vendor的属性设置权限,但是允许获取特定的属性组的权限,以上述的属性设置为例,设置方法如下:
persist.vendor.tp.name
persist.vendor.tp.path
可以找到是对这2个属性进行了设置和读取。
+type vendor_tp_prop, property_type, vendor_property_type;
set_prop(multi_tpinsmod, vendor_tp_prop)