Skip to content

Conversation

@JianyuWang0623
Copy link
Member

Summary

Pick from Gerrit(review passed, not merged):

208fd0b system/init: Parse default cpu-specific configs
21a3041 system/init: Handle trailing file '\0'
48557d3 system/init: Add boot support for action

Pick from Gerrit(merged):

c300999 system/init: Add reboot_on_failure for service
f983d8b system/init: Add exec_start support for action
e65904e system/init: Add oneshot support for service
55d99fd system/init: Warning for long commands
c50bad1 system/init: Add NSH builtin support for action
024910b system/init: Add class start/stop for service
7bdbfb0 system/init: Add system init

Add system init

Refer to the implementation of Android Init Language, consists of five broad classes of statements: Actions, Commands, Services, Options, and Imports.

Actions support two types of triggers: event and action. Action triggers also support runtime triggering. Services support lifecycle management, including automatic restart (at specified intervals), and starting/stopping individually or by class. Import supports files or directories, and we may add a static method in the future. The following are some differences:

  1. The Android Init Language treats lines starting with # as comments, while we use a preprocessor to handle comments.
  2. For action commands, we can omit "exec" and directly execute built-in apps or nsh builtins.
  3. Regarding the property service, users can either adapt it by self or directly use the preset NVS-based properties.
  4. Only part of standard action commands and service options are implemented currlently.

To enable system/init:

-CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INIT_ENTRYPOINT="init_main"
+CONFIG_SYSTEM_INIT=y

For format and additional details, refer to: https://android.googlesource.com/platform/system/core/+/master/init/README.md

Add class start/stop for service

Usage:

      class_start <classname>
      class_stop <classname>

Add NSH builtin support for action

Enable CONFIG_SYSTEM_SYSTEM to support nsh builtins, which depends on nsh.

Warning for long commands

If the command of an action takes too long (greater than CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW milliseconds, 50 ms by default), a warning log will be output for analysis and debugging.

For example:

  1. sleep 1
     [    0.340000] [ 3] [ 0] init_main: executing NSH command 'sleep 1'
     [    1.360000] [ 3] [ 0] init_main: NSH command 'sleep 1' exited 0
   > [    1.360000] [ 3] [ 0] init_main: command 'sleep' took 1020 ms
  1. hello (add sleep(1) to examples/hello)
     [    1.390000] [ 3] [ 0] init_main: executed command 'hello' pid 14
     [    1.390000] [ 3] [ 0] init_main: waiting 'hello' pid 14
     Hello, World!!
   > [    2.400000] [ 3] [ 0] init_main: command 'hello' pid 14 took 1010 ms
     [    2.400000] [ 3] [ 0] init_main: command 'hello' pid 14 exited status 0

Add oneshot support for service

Add support for the oneshot option to the service.

Test

  • RC
    service telnet telnetd
        class test
  >     oneshot
        restart_period 3000
  • Runtime
   [    0.150000] [ 3] [ 0] init_main: == Dump Services ==
   ...
   [    0.160000] [ 3] [ 0] init_main: Service 0x40486aa8 name 'telnet' path 'telnetd'
   [    0.160000] [ 3] [ 0] init_main:   pid: 0
   [    0.160000] [ 3] [ 0] init_main:   arguments:
   [    0.160000] [ 3] [ 0] init_main:       [0] 'service'
   [    0.160000] [ 3] [ 0] init_main:       [1] 'telnet'
   [    0.160000] [ 3] [ 0] init_main:       [2] 'telnetd'
   [    0.160000] [ 3] [ 0] init_main:   classes:
   [    0.160000] [ 3] [ 0] init_main:     'test'
   [    0.170000] [ 3] [ 0] init_main:   restart_period: 3000
   [    0.170000] [ 3] [ 0] init_main:   reboot_on_failure: -1
   [    0.170000] [ 3] [ 0] init_main:   flags:
 > [    0.170000] [ 3] [ 0] init_main:     'oneshot'
   ...
   [    0.370000] [ 3] [ 0] init_main: starting service 'telnet' ...
   [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x2 add 0x4
   [    0.380000] [ 3] [ 0] init_main:   +flag 'running'
   [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x8
   [    0.380000] [ 3] [ 0] init_main:   -flag 'restarting'
   [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x1
   [    0.380000] [ 3] [ 0] init_main:   -flag 'disabled'
   [    0.380000] [ 3] [ 0] init_main: started service 'telnet' pid 9
   ...
   nsh> kill -9 9
   nsh> [    7.350000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x4
   [    7.350000] [ 3] [ 0] init_main:   -flag 'running'
   [    7.350000] [ 3] [ 0] init_main: service 'telnet' flag 0x2 add 0x80000001
   [    7.350000] [ 3] [ 0] init_main:   +flag 'disabled'
   [    7.350000] [ 3] [ 0] init_main:   +flag 'remove'
   [    7.350000] [ 3] [ 0] init_main: service 'telnet' pid 9 exited status 1
 > [    7.360000] [ 3] [ 0] init_main: removing service 'telnet' ...

Add exec_start support for action

Format: exec_start <service>

Start the specified service and pause the processing of any additional initialization commands until the service completes its execution. This command operates similarly to the exec command; the key difference is that it utilizes an existing service definition rather than requiring the exec argument vector.

This feature is particularly intended for use with the reboot_on_failure built-in command to perform all types of essential checks during system boot.

Add reboot_on_failure for service

Add support for the reboot_on_failure option to the service.

When the execution of a command within a certain action fails (returning a non-zero status code), init will continue to execute subsequent commands or actions and will not proactively terminate the startup process. To implement the functionality of "terminating the startup process after a command execution fails", there are two methods:

  1. Execute conditional statements (if/then/else/fi) via exec command, but this depends on sh:
    on init
        exec -- set +e; \
                mount -t fatfs /dev/data /data ; \
                if [ $? -ne 0 ] ; \
                then \
                  echo "failed" ; \
                  reboot ; \
                else \
                  echo "succeed" ; \
                fi;
    
  2. Via service's oneshot + reboot_on_failure:
    Although the example uses sh, it does not depend on it and can be replaced with any other Builtin Apps.
    on init
        exec_start mkdir_tmp
        ls /tmp
    
    service mkdir_tmp sh -c "mkdir /tmp"
        reboot_on_failure 0
        oneshot
    

Test

  • RC
    service console sh
        class core
        override
  >     reboot_on_failure 0
        restart_period 10000
  • Runtime
    [    0.150000] [ 3] [ 0] init_main: == Dump Services ==
    ...
    [    0.170000] [ 3] [ 0] init_main: Service 0x40486ea0 name 'console' path 'sh'
    [    0.170000] [ 3] [ 0] init_main:   pid: 0
    [    0.170000] [ 3] [ 0] init_main:   arguments:
    [    0.170000] [ 3] [ 0] init_main:       [0] 'service'
    [    0.170000] [ 3] [ 0] init_main:       [1] 'console'
    [    0.170000] [ 3] [ 0] init_main:       [2] 'sh'
    [    0.170000] [ 3] [ 0] init_main:   classes:
    [    0.170000] [ 3] [ 0] init_main:     'core'
    [    0.170000] [ 3] [ 0] init_main:   restart_period: 10000
  > [    0.170000] [ 3] [ 0] init_main:   reboot_on_failure: 0
    [    0.170000] [ 3] [ 0] init_main:   flags:
    [    0.170000] [ 3] [ 0] init_main:     'override'
    ...
    [    0.380000] [ 3] [ 0] init_main: started service 'console' pid 4
    ...
    nsh> kill -9 4
    [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000004 add 0x4
    [    8.060000] [ 3] [ 0] init_main:   -flag 'running'
    [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000000 add 0x8
    [    8.060000] [ 3] [ 0] init_main:   +flag 'restarting'
  > [    8.060000] [ 3] [ 0] init_main: Error reboot on failure of service 'console' reason 0

Add boot support for action

Add support for booting a new application firmware image, depends on BOARDCTL_BOOT_IMAGE.
When the built-in boot command of nsh is enabled, the built-in boot command of Init will take precedence (see init_builtin_run()). To use the built-in boot command of nsh, use: exec -- sh boot [args...].
Referred to nshlib/nsh_syscmds.c: cmd_boot()

Handle trailing file '\0'

When ETC_ROMFS is disabled to reduce the bin size, we can provide the init.rc file via a pseudo-file in the boards/vendor directory. For example:

- CONFIG_ETC_ROMFS=n
- CONFIG_PSEUDOFS_FILE=y
- CONFIG_DISABLE_PSEUDOFS_OPERATIONS=n
FAR const char *init_rc =
  "on init\n"
  "    start console\n";
  "service console sh\n"
  "    restart_period 100\n";

int fd = open("/etc/init.d/init.rc", O_WRONLY | O_CREAT);
/* ... */
ssize_t n = write(fd, init_rc, strlen(init_rc) + 1);
/* ... */
close(fd);

The last character '\0' in the file content will be treated as a new line, and the number of parsed parameters will be zero (abnormal, there should be at least one keyword)

Parse default cpu-specific configs

On the basis of init.rc, add default parsing of cpu-specific configs.

  • /etc/init.d/init.rc
  • /etc/init.d/init.cpu${CPUID}.rc

Refactor function init_parse_configs() to parse files from the default path instead of identifying and parsing directories or files, as the functionality is unnecessary.

Impact

The newly added component can be used for user space system initialization and daemon process management.

Testing

  • Please see logs above for selftest
  • CI

Refer to the implementation of Android Init Language, consists of five broad
classes of statements: Actions, Commands, Services, Options, and Imports.

Actions support two types of triggers: event and action. Action triggers also
support runtime triggering. Services support lifecycle management, including
automatic restart (at specified intervals), and starting/stopping
individually or by class. Import supports files or directories, and we may
add a static method in the future. The following are some differences:
  1. The Android Init Language treats lines starting with `#` as comments,
     while we use a preprocessor to handle comments.
  2. For action commands, we can omit "exec" and directly execute
     built-in apps or nsh builtins.
  3. Regarding the property service, users can either adapt it by self or
     directly use the preset NVS-based properties.
  4. Only part of standard action commands and service options are
     implemented currlently.

To enable system/init:
  ```diff
  -CONFIG_INIT_ENTRYPOINT="nsh_main"
  +CONFIG_INIT_ENTRYPOINT="init_main"
  +CONFIG_SYSTEM_INIT=y
  ```

For format and additional details, refer to:
  https://android.googlesource.com/platform/system/core/+/
  master/init/README.md

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Usage:
  class_start <classname>
  class_stop <classname>

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Enable CONFIG_SYSTEM_SYSTEM to support nsh builtins, which depends on nsh.

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
If the command of an action takes too long (greater than
CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW milliseconds, 50 ms by default),
a warning log will be output for analysis and debugging.

For example:

  a. sleep 1
       [    0.340000] [ 3] [ 0] init_main: executing NSH command 'sleep 1'
       [    1.360000] [ 3] [ 0] init_main: NSH command 'sleep 1' exited 0
     > [    1.360000] [ 3] [ 0] init_main: command 'sleep' took 1020 ms

  b. hello (add sleep(1) to examples/hello)

       [    1.390000] [ 3] [ 0] init_main: executed command 'hello' pid 14
       [    1.390000] [ 3] [ 0] init_main: waiting 'hello' pid 14
       Hello, World!!
     > [    2.400000] [ 3] [ 0] init_main: command 'hello' pid 14 took 1010 ms
       [    2.400000] [ 3] [ 0] init_main: command 'hello' pid 14 exited status 0

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Add support for the oneshot option to the service.

Test
  - RC
      service telnet telnetd
          class test
    >     oneshot
          restart_period 3000
  - Runtime
      [    0.150000] [ 3] [ 0] init_main: == Dump Services ==
      ...
      [    0.160000] [ 3] [ 0] init_main: Service 0x40486aa8 name 'telnet' path 'telnetd'
      [    0.160000] [ 3] [ 0] init_main:   pid: 0
      [    0.160000] [ 3] [ 0] init_main:   arguments:
      [    0.160000] [ 3] [ 0] init_main:       [0] 'service'
      [    0.160000] [ 3] [ 0] init_main:       [1] 'telnet'
      [    0.160000] [ 3] [ 0] init_main:       [2] 'telnetd'
      [    0.160000] [ 3] [ 0] init_main:   classes:
      [    0.160000] [ 3] [ 0] init_main:     'test'
      [    0.170000] [ 3] [ 0] init_main:   restart_period: 3000
      [    0.170000] [ 3] [ 0] init_main:   reboot_on_failure: -1
      [    0.170000] [ 3] [ 0] init_main:   flags:
    > [    0.170000] [ 3] [ 0] init_main:     'oneshot'
      ...
      [    0.370000] [ 3] [ 0] init_main: starting service 'telnet' ...
      [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x2 add 0x4
      [    0.380000] [ 3] [ 0] init_main:   +flag 'running'
      [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x8
      [    0.380000] [ 3] [ 0] init_main:   -flag 'restarting'
      [    0.380000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x1
      [    0.380000] [ 3] [ 0] init_main:   -flag 'disabled'
      [    0.380000] [ 3] [ 0] init_main: started service 'telnet' pid 9
      ...
      nsh> kill -9 9
      nsh> [    7.350000] [ 3] [ 0] init_main: service 'telnet' flag 0x6 add 0x4
      [    7.350000] [ 3] [ 0] init_main:   -flag 'running'
      [    7.350000] [ 3] [ 0] init_main: service 'telnet' flag 0x2 add 0x80000001
      [    7.350000] [ 3] [ 0] init_main:   +flag 'disabled'
      [    7.350000] [ 3] [ 0] init_main:   +flag 'remove'
      [    7.350000] [ 3] [ 0] init_main: service 'telnet' pid 9 exited status 1
    > [    7.360000] [ 3] [ 0] init_main: removing service 'telnet' ...

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Format: exec_start <service>

Start the specified service and pause the processing of any additional
initialization commands until the service completes its execution. This
command operates similarly to the `exec` command; the key difference is
that it utilizes an existing service definition rather than requiring
the `exec` argument vector.

This feature is particularly intended for use with the `reboot_on_failure`
built-in command to perform all types of essential checks during system boot.

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Add support for the reboot_on_failure option to the service.

When the execution of a command within a certain action fails (returning
a non-zero status code), init will continue to execute subsequent commands or
actions and will not proactively terminate the startup process. To implement
the functionality of "terminating the startup process after a command
execution fails", there are two methods:
a. Execute conditional statements (if/then/else/fi) via exec command,
   but this depends on sh:
   ```
   on init
       exec -- set +e; \
               mount -t fatfs /dev/data /data ; \
               if [ $? -ne 0 ] ; \
               then \
                 echo "failed" ; \
                 reboot ; \
               else \
                 echo "succeed" ; \
               fi;
   ```
b. Via service's oneshot + reboot_on_failure:
   /* Although the example uses sh, it does not depend on it and can be
    * replaced with any other Builtin Apps.
    */
   ```
   on init
       exec_start mkdir_tmp
       ls /tmp

   service mkdir_tmp sh -c "mkdir /tmp"
       reboot_on_failure 0
       oneshot
   ```

Test
  - RC
      service console sh
          class core
          override
    >     reboot_on_failure 0
          restart_period 10000
  - Runtime
      [    0.150000] [ 3] [ 0] init_main: == Dump Services ==
      ...
      [    0.170000] [ 3] [ 0] init_main: Service 0x40486ea0 name 'console' path 'sh'
      [    0.170000] [ 3] [ 0] init_main:   pid: 0
      [    0.170000] [ 3] [ 0] init_main:   arguments:
      [    0.170000] [ 3] [ 0] init_main:       [0] 'service'
      [    0.170000] [ 3] [ 0] init_main:       [1] 'console'
      [    0.170000] [ 3] [ 0] init_main:       [2] 'sh'
      [    0.170000] [ 3] [ 0] init_main:   classes:
      [    0.170000] [ 3] [ 0] init_main:     'core'
      [    0.170000] [ 3] [ 0] init_main:   restart_period: 10000
    > [    0.170000] [ 3] [ 0] init_main:   reboot_on_failure: 0
      [    0.170000] [ 3] [ 0] init_main:   flags:
      [    0.170000] [ 3] [ 0] init_main:     'override'
      ...
      [    0.380000] [ 3] [ 0] init_main: started service 'console' pid 4
      ...
      nsh> kill -9 4
      [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000004 add 0x4
      [    8.060000] [ 3] [ 0] init_main:   -flag 'running'
      [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000000 add 0x8
      [    8.060000] [ 3] [ 0] init_main:   +flag 'restarting'
    > [    8.060000] [ 3] [ 0] init_main: Error reboot on failure of service 'console' reason 0

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Add support for booting a new application firmware image.
Depends on `BOARDCTL_BOOT_IMAGE`.

When the built-in boot command of nsh is enabled, the built-in boot
command of Init will take precedence (see init_builtin_run()). To use
the built-in boot command of nsh, use: `exec -- sh boot [args...]`.

Referred to nshlib/nsh_syscmds.c: cmd_boot()

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
When ETC_ROMFS is disabled to reduce the bin size, we can provide the init.rc
file via a pseudo-file in the boards/vendor directory. For example:
  - CONFIG_ETC_ROMFS=n
  - CONFIG_PSEUDOFS_FILE=y
  - CONFIG_DISABLE_PSEUDOFS_OPERATIONS=n
  ```C
  FAR const char *init_rc =
    "on init\n"
    "    start console\n";
    "service console sh\n"
    "    restart_period 100\n";

  int fd = open("/etc/init.d/init.rc", O_WRONLY | O_CREAT);
  /* ... */
  ssize_t n = write(fd, init_rc, strlen(init_rc) + 1);
  /* ... */
  close(fd);
  ```

The last character '\0' in the file content will be treated as a new line,
and the number of parsed parameters will be zero (abnormal, there should be
at least one keyword).

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
On the basis of init.rc, add default parsing of cpu-specific configs.
- /etc/init.d/init.rc
- /etc/init.d/init.cpu${CPUID}.rc

Refactor function `init_parse_configs()` to parse files from the default path
instead of identifying and parsing directories or files, as the functionality
is unnecessary.

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
@JianyuWang0623 JianyuWang0623 marked this pull request as draft October 27, 2025 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants