配置安卓服务自启动

在完成GDK8的Ubuntu武城版本镜像之后,格蠹的小伙伴们又开始制作GDK8安卓的镜像,也顺便记录一下踩过的坑,比如本篇文章介绍的安卓服务自启动的配置过程。

init.rc文件

第一次看到init.rc时,感觉这个文件跟Linux下面的rc.local好像有点类似,打开一看,里面又是exec又是start,还有mkdir chown这样命令,看来写好init.rc文件,ndstub服务就可以实现自启动了!阅读了init源代码中的README.md后,更加确认了我的想法。

Init .rc Files
--------------
The init language is used in plain text files that take the .rc file
extension.  There are typically multiple of these in multiple
locations on the system, described below.

/init.rc is the primary .rc file and is loaded by the init executable
at the beginning of its execution.  It is responsible for the initial
set up of the system.

Init loads all of the files contained within the
/{system,vendor,odm}/etc/init/ directories immediately after loading
the primary /init.rc.  This is explained in more details in the
Imports section of this file.

Legacy devices without the first stage mount mechanism previously were
able to import init scripts during mount_all, however that is deprecated
and not allowed for devices launching after Q.

The intention of these directories is:

   1. /system/etc/init/ is for core system items such as
      SurfaceFlinger, MediaService, and logd.
   2. /vendor/etc/init/ is for SoC vendor items such as actions or
      daemons needed for core SoC functionality.
   3. /odm/etc/init/ is for device manufacturer items such as
      actions or daemons needed for motion sensor or other peripheral
      functionality.

All services whose binaries reside on the system, vendor, or odm
partitions should have their service entries placed into a
corresponding init .rc file, located in the /etc/init/
directory of the partition where they reside.  There is a build
system macro, LOCAL\_INIT\_RC, that handles this for developers.  Each
init .rc file should additionally contain any actions associated with
its service.

在init.rc的文件内添加下面的内容,然后重新刷机。

start ndstub
service ndstub /system/bin/ndstub
    class core

SELinux

SELinux是Linux中一款非常优秀的安全子系统,其作用在于对所有进程强制执行强制访问控制;而基于Linux内核的安卓系统为了保证自身的安全性,当然也不会将SELinux剔除在外。
虽然SELinux保障了系统的安全性,但是对于黑客、开发人员(或许应该是但指对安卓不熟悉的开发人员)等造成一定的困扰,因为想要干点啥,都会被SElinux这只拦路虎给拦住!
没有武松的实力,不能打虎,好听的解释就是,只是为了让服务启动,没这个必要这么做,如是只能顺着他规则去做,做一个听话的宝宝。

开机后马上打开Nano Code测试一下,能不能连上ndstub,但是提示连接不上,于是马上用adb连到机器上面去看一下,先看看dmesg里面有没有重要信息,果然安卓非常贴心的打出来了提示。

[    9.030975] init: Could not start service 'ndstub' as part of class 'core': File /system/bin/ndstub(labeled "u:object_r:system_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials
rk3328_box:/ #

和安全有关,想必就是SELinux在捣鬼了,再看一下SELinux的模式,无论是Kernel command line还是getenforce,都显示SELinux是宽容模式啊,按理说不应该阻止服务启动的。

[    0.000000] Kernel command line: storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal  androidboot.dtb_idx=0 androidboot.dtbo_idx=0  androidboot.verifiedbootstate=orange androidboot.slot_suffix= androidboot.serialno=JPX53POBYZ console=ttyFIQ0 androidboot.baseband=N/A androidboot.wificountrycode=CN androidboot.veritymode=enforcing androidboot.hardware=rk30board androidboot.console=ttyFIQ0 androidboot.verifiedbootstate=orange firmware_class.path=/vendor/etc/firmware init=/init rootwait ro loop.max_part=7 androidboot.selinux=permissive buildvariant=userdebug earlycon=uart8250,mmio32,0xff130000 swiotlb=1 kpti=0 coherent_pool=1m androidboot.boot_devices=ff520000.dwmmc
rk3328_box:/ # getenforce
getenforce
Permissive

不过按理说归按理说,还是要根据安卓给出的提示连接上面的步骤重新做一下
https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials
照葫芦画瓢添加ndstub.rc、ndstub.te文件,并在file_contexts(与te文件同目录)添加ndstub的配置,再重新刷机!

ndstub.rc
service ndstub /system/bin/ndstub
    class core

ndstub.te
# ndstub service
type ndstub, domain;
type ndstub_exec, exec_type, file_type;

init_daemon_domain(ndstub)

file_contexts
/system/bin/ndstub   u:object_r:ndstub _exec:s0

防火墙

刷完机后,重新用Nano Code连一次ndstub,按照官方文档的做法,结果不用想。。。
还是有问题。。。
先看一下进程在不在。

rk3328_box:/ # ps -A | grep ndstub
ps -A | grep ndstub
root            295      1 10810088  5728 futex_wait_queue_me 0 S ndstub

还好进程还在,看来是有官方文档内没提出来的坑在啊!
再看端口号,07e5就是2021啊。

rk3328_box:/ # cat /proc/net/tcp
cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                        
   0: 00000000:07E5 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 17030 1 0000000000000000 100 0 0 10 0
   1: 0601A8C0:07E5 0501A8C0:C87A 01 00000000:00000000 00:00000000 00000000     0        0 17031 1 0000000000000000 20 4 0 10 -1
rk3328_box:/ #

进程有,端口号也正常,难道是防火墙捣鬼?先赶紧手动修改一下防火墙规则,看看有没有用。

iptables -P INPUT   ACCEPT
iptables -P OUTPUT  ACCEPT
iptables -P FORWARD ACCEPT
ip6tables -P INPUT   ACCEPT
ip6tables -P OUTPUT  ACCEPT
ip6tables -P FORWARD ACCEPT

再尝试一次,成功!!!

总结

  1. 编写xxxx.rc文件。
基本格式(可根据需求进行添加):
service xxxx /system/bin/xxxx
    class core
  1. 编写xxxx.te文件
基本格式(可根据需求进行添加):
# xxxx service
type xxxx, domain;
type xxxx_exec, exec_type, file_type;

init_daemon_domain(xxxx)
  1. 为/system/bin/xxxx添加标签
找到file_contexts文件,与.te文件处于同一目录内
/system/bin/xxxx   u:object_r:xxxx_exec:s0

参考

https://source.android.google.cn/security/selinux?hl=zh-cn
https://events.static.linuxfound.org/sites/events/files/slides/abs2014_seforandroid_smalley.pdf