MTK Android 8.1下新增开机服务

Android在启动过程中,第一个启动的用户态进程init会读取的启动脚本文件,主要完成一些初级的初始化,这些脚本文件以rc作为后缀名,它是"run commands"的缩写。并在/system/core/init/init.c中解析。rc文件被拆分成了各种类型,主文件为init.rc,其余根据功能还有设备进行了拆分,比如init.zygote32.rc和init.mt6763.rc。如果想要配置开机启动服务,需要修改rc文件。常用的方法有两种,常见的就是在源码里修改,然后重新编译。不想重新编译源码的话就使用boot image的解包和打包工具直接编辑image中的文件。

1 添加可执行文件

本文的场景是需要在系统中添加一个prebuilt可执行文件httpshell,向外暴露http服务,并需要实现开启自启动。首先在system/core下新建httpshell文件夹,将可执行文件拷入文件夹内,然后新建Android.mk文件,添加如下内容:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := httpshell
LOCAL_MODULE := httpshell
LOCAL_MODULE_PATH := $(TARGET_OUT)/bin
LOCAL_MODULE_CLASS := EXECUTABLES
include $(BUILD_PREBUILT) 

然后执行make snod命令,重新生成system.img文件,在手机的system/bin目录下会看到我们添加的httpshell文件。现在完成了文件的添加,接下来还需要修改启动脚本文件,完成开机自启动。

2 修改rc文件

这里使用第一种方式,也就是在源码中修改。我这里的平台为mtk6763,可以选择修改主文件init.rc或者device/mtk/mt6763下的init.mt6763.rc文件。区别在于前者的改动体现在boot.img,后者的改动体现在vendor.img。在选定的rc文件中添加如下内容。然后重新编译boot.img或者vendor.img,烧录即可。

service httpshell /system/bin/httpshell
  class main
  user root
  group root
  disabled
  seclabel u:r:httpshell:s0

直接重启手机,发现提示 Service xxx does not have a SELinux domain defined 错误,表明需要指定selinux domain。

3 配置selinux权限

重新开机,使用dmesg命令查看kernel log,会提示以下错误。这种错误一般就两种情况,第一,可执行文件不存在,例如上面的案例中的/system/bin/httpshell不存在。就需要要查看手机里面改文件是否存在,对应的权限是否正确;第二,新增service的sepolicy配置不当。

init: cannot setexeccon('u:r:httpshell:s0'): Invalid argument

经过核查,发现httpshell没有配置正确的selinux配置文件。需要添加配置内容,需要注意的是android 8.0之后对权限做了分离,Sepolicy权限发生了变化,device/XXX/YYY/sepolicy存储在vendor.img中,假设修改的权限在该目录中,就要重新编译然后刷入vendor.img到手机中。

  1. 创建文件夹

    在device/mtk/mt6763/sepolicy下创建httpshell文件夹

  2. 创建file_contexts

    在httpshell文件夹内新建file_contexts文件,添加以下内容:

    /system/bin/httpshell             u:object_r:httpshell_exec:s0
    
  3. 添加te文件

    在文件夹中新增httpshell.te文件,并添加以下内容

    type httpshell, domain;
    type httpshell_exec, exec_type, file_type;
    
    init_daemon_domain(httpshell)
    

完成以上步骤之后,如果手机的selinux工作模式为enforce的话,服务仍然会启动失败,但是在permissive模式下,服务依然正常运行,但是会在kernel log下打印授权信息。可以通过 dmesg | grep avc > /sdcard/avc_log.txt 命令截取授权失败的信息,然后通过 policycoreutils 工具执行 audit2allow -i avc_log.txt 对日志进行解析,把解析出来的条目增加到httpshell.te中。然后再编辑/system/sepolicy/domain.te文件,添加 neverallow { -httpshell } { file_type -exec_type -postinstall_file }:file entrypoint; 即可。