Android系统10 RK3399 init进程启动(四十一) 最新最详细的init.rc语法讲解

配套系列教学视频链接:

      安卓系列教程之ROM系统开发-百问100ask

说明

系统:Android10.0

设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)

前言

这个章节我们详细的来学习一下init.rc中各种语法, 深入了解init.rc 各种细节。


一, 基本语法规则

Init.rc 中的语法都是Android自定义的, system/core/init/README.md有具体语法说明 ,整个init.rc 其实有以下几个部分组成:

Imports

导入其他rc文件

Actions

命令的集合, 形式为on trigger,  其中trigger有两种, event和proptery。

Commands

隶属于Action中的命令

Services

后台服务, 一般都是C/C++的守护进程,或者是shell脚本

Options

隶属于Service中选项, 比如守护进程的用户id, 组id, 类别 , 是否执行一次, 创建额外套接字等。

 其他规则:

  1. #号作为注释。
  2. 一行为单位, 以空格作为分隔符, 行尾可以用反斜杠'\'表示连接下一行。
  3. 字符串中可以使用双引号(如“  ”)来表示空格。
  4. ${property.name} 可以展开属性。
  5. 以import, on, service开头的, 都表示一个section(段落), 意味着一个关键词出现之后到出现第二个关键词之前, 关键词后面的内容都属于一个section。
  6. Service的关键词在所有的rc文件中都必须是唯一的, 如果出现第二个相同的service名字, 将会忽略和显示日志。
  7. Action可以在多个rc文件出现,比如on boot可以出现在init.rc , 也可以出现在/vendor/etc/init/hw/init.rk30board.rc中。

 二, init.rc 示例

import /init.environ.rc

import /init.usb.rc

import /init.${ro.hardware}.rc

import /vendor/etc/init/hw/init.${ro.hardware}.rc

import /init.usb.configfs.rc

import /init.${ro.zygote}.rc

# Cgroups are mounted right before early-init using list from /etc/cgroups.json

on early-init

    # Disable sysrq from keyboard

    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.

restorecon /adb_keys

service ueventd /system/bin/ueventd

    class core

    critical

    seclabel u:r:ueventd:s0

    shutdown critical

on property:ro.debuggable=1

    # Give writes to anyone for the trace folder on debug builds.

    # The folder is used to store method traces.

    chmod 0773 /data/misc/trace

    # Give reads to anyone for the window trace folder on debug builds.

    chmod 0775 /data/misc/wmtrace

    start console

 三, rc文件介绍

早期的rc文件的内容都集中在/init.rc中, 大部分的service定义也是集中在这个文件中, 同时有可能会出现service对应的可执行程序没有编译进系统, 导致service执行失败的情形, 现在各种rc文件是分散在不同分区中进行模块化,并且service对应代码和rc文件是一起编译的, 这样保证模块化的完整性。

/init.rc

最主要和最早被加载的rc文件, 一般都是做系统最初初始化的。

/init.${ro.hardware}.rc

/vendor/etc/init/hw/init.${ro.hardware}.rc

Soc对应的定制的初始化命令和服务。

/system/etc/init/

启动系统核心的服务,比如 SurfaceFlinger, MediaService, and logcatd。

/vendor/etc/init/

SOC厂商定制开机自启动的serviced对应的rc脚本,比如gnss,camera,sensor,drm等HAL相关服务

/odm/etc/init/

外设设备厂商定制自启动的serviced对应的rc脚本, 如运动传感器或其他外围设备所需的命令和服务。

四, Action动作

Action其实就是一组命令的集合, 它有一个trigger触发器,当系统中出现与动作的触发器匹配的事件,这个Action就会被加入到执行队列的尾部, 等到这个Action执行时, Action中包含的所有命令将会按照先后顺序执行, 格式:

    on <trigger> [&& <trigger>]*

       <command>

       <command>

       <command>

trigger作为触发器,trigger有两种, event和proptery。

command: 类似shell命令,但是并不是shell命令, 因为这些命令是在init进程中单独实现的, 而命令行我们执行的shell命令, 是在toolbox中实现的, 并且rc脚本中的command的数量有限。

Action的示例:

on early-init

    # Disable sysrq from keyboard

    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.

restorecon /adb_keys

on property:ro.debuggable=1

    # Give writes to anyone for the trace folder on debug builds.

    # The folder is used to store method traces.

    chmod 0773 /data/misc/trace

    # Give reads to anyone for the window trace folder on debug builds.

    chmod 0775 /data/misc/wmtrace

    start console

触发器在哪里触发呢: 一般在init的代码中,如:system/core/init/init.cpp

am.QueueEventTrigger("early-init");

am.QueueEventTrigger("late-init");

 或者在rc文件中, 如:

on late-init

    trigger early-fs

    trigger fs

on post-fs

    exec - system system -- /system/bin/vdc checkpoint markBootAttempt

常见的trigger:

on early-init               #早期初始化

on boot                   #系统启动触发

on init                     #在初始化时触发

on late-init                #在初始化晚期阶段触发

on charger                  #当充电时触发

on property:<key>=<value>   #当属性值满足条件时触发

on post-fs                  #挂载文件系统

on post-fs-data             #挂载data

常见的command:

大部分的命令都在system/core/init/builtins.cpp代码中实现:

// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map builtin_functions = {
        {"bootchart",               {1,     1,    {false,  do_bootchart}}},
        {"chmod",                   {2,     2,    {true,   do_chmod}}},
        {"chown",                   {2,     3,    {true,   do_chown}}},
        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
        {"class_start",             {1,     1,    {false,  do_class_start}}},
        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
        {"copy",                    {2,     2,    {true,   do_copy}}},
        {"domainname",              {1,     1,    {true,   do_domainname}}},
        {"enable",                  {1,     1,    {false,  do_enable}}},
        {"exec",                    {1,     kMax, {false,  do_exec}}},
        {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
        {"exec_start",              {1,     1,    {false,  do_exec_start}}},
        {"export",                  {2,     2,    {false,  do_export}}},
        {"hostname",                {1,     1,    {true,   do_hostname}}},
        {"ifup",                    {1,     1,    {true,   do_ifup}}},
        {"init_user0",              {0,     0,    {false,  do_init_user0}}},
        {"insmod",                  {1,     kMax, {true,   do_insmod}}},
        {"installkey",              {1,     1,    {false,  do_installkey}}},
        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
        {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
        // TODO: Do mount operations in vendor_init.
        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
        // mount and umount are run in the same context as mount_all for symmetry.
        {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"restart",                 {1,     1,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
        {"rm",                      {1,     1,    {true,   do_rm}}},
        {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
        {"setprop",                 {2,     2,    {true,   do_setprop}}},
        {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
        {"start",                   {1,     1,    {false,  do_start}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
        {"verity_load_state",       {0,     0,    {false,  do_verity_load_state}}},
        {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
        {"wait",                    {1,     2,    {true,   do_wait}}},
        {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
        {"write",                   {2,     2,    {true,   do_write}}},
    };
    // clang-format on
    return builtin_functions;
}

 特殊的几个命令:

bootchart

启动或终止bootcharting, bootcharting是用于分析系统启动时间的。

格式: bootchart [start|stop]

class_reset/class_restart

class_start/class_stop

复位/重启/启动/停止某一类的所有Service,语法:

class_start <serviceclass>

例子: class_reset main

copy

拷贝, 和shell命令cp一样

例子: copy /proc/cmdline /dev/urandom

domainname

设置域名

例子: domainname localdomain

enable

将一个Service的标志从disable改成enable

语法: enable <servicename>

例子:

on property:ro.boot.myfancyhardware=1

        enable my_fancy_service_for_my_fancy_hardware

exec

启动一个只执行一次的临时Service,

语法:exec [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]

exec - system system -- /system/bin/vdc checkpoint markBootAttempt

exec_start

启动一个特定的Service, 语法

exec_start service_name

例子: exec_start apexd-bootstrap

ifup 

启动网络接口, 语法: ifup <interface>

insmod

加载ko驱动,格式:insmod [-f] <path> [<options>]

例子: insmod /vendor/lib/modules/8822bs.ko

setrlimit

设置系统资源使用限制,linux下每种资源都有相关的软硬限制,软限制是内核强加给相应资源的限制值,硬限制是软限制的最大值。

语法: setrlinit  <resource>  <cur>  <max>

<resource>有: cpu, fsize, stack, nice等

<cur>表示软限制,<max>表示硬限制, 值如果为unlimited表示最大值

start/stop/restart

启动/停止/重启指定的服务 格式: start <servicename>

symlink

符号链接, 类似shell命令中的ln -s

格式: symlink <target> <sym_link>

sysclktz

设置当前系统时钟值, sysclktz 0就表示将系统时钟设置成GMT 0

trigger

触发特定的action的触发器

例子: trigger early-fs

wait_for_prop

等待特定的属性变成特定的值

例子: wait_for_prop apexd.status ready

wait

在指定时间内等待特定文件的出现

格式: wait <file_path> [timeout]

 五, Service服务

Service表示一个开机自启动服务, 服务可以常驻型(不死型), 也可以是只执行一次, 可以选择开机自启动或者在特定的时候启动,语法:

service <name> <pathname> [ <argument> ]*

       <option>

       <option>

       ...

<name> service的名字,要保证唯一

<pathname> service对应的可执行程序路径

<argument> 启动service所带的参数

<option>  启动service时约束和附加选项,它影响着服务以什么方式和什么时候启动,

具体参考system/core/init/README.md

常见的option如下所示:

capabilities [ <capability>\* ]

为启动的服务设置能力, 在执行特权操作时,如果进程的有效身份不是 root,就去检查是否具有该特权操作所对应的 capabilites,并以此决定是否可以进行该特权操作。比如要向进程发送信号(kill()),就得具有 capability CAP_KILL;如果设置系统时间,就得具有 capability CAP_SYS_TIME。

class <name> [ <name>\* ]

为服务设置类别, 非常重要, 设置之后,系统就可以批量启动或停止一类服务。

console [<console>]

critical

表示这是一个对设备至关重要的一个服务,如果它在四分钟内退出超过四次,则设备将重启进入恢复模式,, 比如zygote服务就是这种。

disabled

此服务不会自动启动,而是需要通过显式调用服务名来启动

file <path> <type>

打开一个文件,并将文件的fd传递给启动的服务, 服务进程中可以通过android_get_control_file()拿到这个fd, <type>可以是"r", "w" or "rw"

setenv<name><value>

设置环境变量<name>为某个值<value>

socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]

创建一个名为/dev/socket/<name>的unix domain socket,然后将它的fd值传给启动它的进程,有效的<type>值包括dgram,stream和seqacket,而user和group的默认值是0,也可以设置进程对应的selinux安全上下文。

user<username>

在启动服务前将用户组切换为<username>,默认情况下用户都是root

group<groupname>[<groupname>]*

在启动服务前将用户组切换为<groupname>,可以是多个用户组

oneshot

只启动一次,当这个服务推出后,不会重启

onrestart

当此服务重启时,需要执行某些命令

writepid <file> [ <file>\* ]

当服务进行fork的时候, 将自进程的pid号写入到指定的文件中,用于cgroup/cpuset

例子:

service logd /system/bin/logd

    socket logd stream 0666 logd logd

    socket logdr seqpacket 0666 logd logd

    socket logdw dgram+passcred 0222 logd logd

    file /proc/kmsg r

    file /dev/kmsg w

    user logd

    group logd system package_info readproc

    capabilities SYSLOG AUDIT_CONTROL SETGID  #允许使用 syslog() 系统调用

    writepid /dev/cpuset/system-background/tasks

 六,总结

init.rc是我们经常修改和开发的文件, 掌握它对我们开发定制有很大的帮助,也是做ROM开发必须要掌握的。 

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 可以使用以下方法重启 Android 系统: 1. 使用 `System.exit(0)` 方法终止应用程序进程。 2. 使用 `android.os.Process.killProcess(android.os.Process.myPid())` 方法杀死应用程序进程。 3. 使用 `PowerManager` 类的 `reboot()` 方法重启设备。 需要注意的是,第 3 种方法只能在系统级别使用,需要在应用程序中声明 `REBOOT` 权限。 例如: ``` PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); pm.reboot(null); ``` 调用 `reboot()` 方法时,可以传入一个字符串参数,表示重启的原因。 ### 回答2: 要使用代码在RK3399 Android 7.1中重启系统,您可以使用以下方法: 1. 使用Runtime类: 您可以使用Runtime类中的exec()方法来执行shell命令。可以执行"reboot"命令来重启系统。以下是一个示例代码片段: ``` try { Runtime.getRuntime().exec("reboot"); } catch (IOException e) { e.printStackTrace(); } ``` 2. 使用PowerManager类: 您可以使用PowerManager类中的reboot()方法来实现重启系统的功能。以下是一个示例代码片段: ``` PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (powerManager != null) { powerManager.reboot(null); } ``` 请注意,为了使用PowerManager类,您需要在AndroidManifest.xml文件中添加相应的权限:<uses-permission android:name="android.permission.REBOOT" /> 3. 使用DevicePolicyManager类: 如果您的应用程序是设备管理员应用程序,您可以使用DevicePolicyManager类中的reboot()方法来实现重启系统的功能。以下是一个示例代码片段: ``` DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName adminComponentName = new ComponentName(this, AdminReceiver.class); // AdminReceiver是自定义的广播接收器类,用于处理设备管理员相关的操作 devicePolicyManager.reboot(adminComponentName); ``` 需要注意的是,如果您的应用程序不是设备管理员应用程序,您需要先设置您的应用程序为设备管理员,才能使用DevicePolicyManager类。 这些是在RK3399 Android 7.1中使用代码重启系统的几种方法。您可以根据您的需求选择适合您的方法。 ### 回答3: 使用RK3399开发板上的Android 7.1系统,我们可以通过编写代码来实现系统的重启。 在Android中,系统重启可以通过调用系统服务的方法来实现。首先,我们需要获取系统服务的一个实例,然后调用相应的方法来实现重启。 具体步骤如下: 1. 获取系统服务的实例。我们可以通过调用`Context.getSystemService()`方法来获取系统服务的实例。在这个例子中,我们可以获取`Context.POWER_SERVICE`服务的实例,该服务用于控制设备的电源。 ```java PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); ``` 2. 通过系统服务实例调用重启方法。获取到`PowerManager`的实例后,我们可以调用`reboot()`方法来实现系统重启。 ```java powerManager.reboot(null); ``` 在这个例子中,`reboot()`方法接受一个字符串参数,用于传递重启的原因。我们传递`null`作为参数,表示没有特定的重启原因。 3. 添加权限。为了调用系统服务,我们需要在AndroidManifest.xml文件中添加适当的权限。在这种情况下,我们需要添加`REBOOT`权限。 ```xml <uses-permission android:name="android.permission.REBOOT" /> ``` 通过编写上述代码,我们可以在RK3399上的Android 7.1系统中实现系统的重启。请注意,系统重启将导致设备重新启动,并且会中断正在运行的任何应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旗浩QH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值