Run commands after boot

Our prototype device (powered by Hikey 960) relies on BT for user input. When the PCB is enclosed in the housing, there are no ports, except for power. It runs AOSP with a MIPI display. A problem with this configuration is that once a user chooses to disable BT, he can no longer control the device. We can fix it by connecting adb over WiFi and run the following script:

adb root
adb shell settings put global airplane_mode_on 0
adb shell svc bluetooth enable
adb shell svc wifi enable

As you can see it also takes care of accidental Airplane and Wifi mode toggles. This works when using adb over usb, but not with adb over wifi. I would instead like to run these commands each time the device boots, but so far I haven’t been able to identify where and when I should run this script. I have tried the on boot section in init.rc (where I placed some other hacks succesfully), but it doesn’t work for these commands, probabaly because it is too early in the boot process.

What would be more suitable location?

init.rc looks like the right place, could you attach modification you have done ? did you try ‘start bluetooth’

Well it’s basically the same as above without the adb shell prefix, put at the end of the on boot section.

Android Init has its own set of commands [1] and svc is not part of it. that why I suggested you to add start bluetooth, start wifi… instead.

[1] init/README.md

on property:sys.boot_completed=1 is probably the right place in the init.rc to run your commands from, HOWEVER, this is not the SHELL, which means that you don’t have access to shell commands. At least not directly.

From Loic’s link, scroll down to the “exec” or “exec_background” commands. You could also define a shell script as a service.

Don’t forget to pay attention to selinux!

Here is an example of exec;
https://android.googlesource.com/device/huawei/angler/+/master/init.angler.rc#69

I have this in my init.rc now:

on property:sys.boot_completed=1
    bootchart stop
    exec - root system -- /system/postboot.sh

This is the result:

[ 13.399564] init: Command ‘exec - root system – /system/postboot.sh’ action=sys.boot_completed=1 (/init.rc:722) took 1ms and failed: Could not start exec service: File /system/postboot.sh(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? Writing SELinux Policy  |  Android Open Source Project

I have tried different labels, including u:r:init:s0, but I get the same message regardless.

I have SELinux running in permissive mode.

Using the information found here: Not able to run the script from init.rc - #6 by Loic , I have now defined a service:

service postboot /system/bin/sh /data/postboot.sh
    class main
    user root
    oneshot

Running into a similar error:

[ 92.370503] init: Could not ctl.start for ‘postboot’: File /system/bin/sh(labeled “u:object_r:shell_exec:s0”) has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? Writing SELinux Policy  |  Android Open Source Project

Then I found this thread: Connecting MCP2515 via SPI for CAN driver with Android kernel 4.9 - #4 by rubberduck203

So I created the shell.te file in device/linaro/hikey/sepolicy/:

init_daemon_domain(shell)

But this doesn’t build for me with a ‘Duplicate declaration of type’ at token ‘;’ ERROR. in checkpolicy. Got the feeling I’m almost there though :slight_smile:

---- UPDATE ----

Also tried the following:

service postboot /system/bin/postboot
    class main
    user root
    oneshot

And created the postboot.te file:

# postboot service
type postboot, domain;
type postboot_exec, exec_type, file_type;

init_daemon_domain(postboot)

/system/bin/postboot is just a shell script:

#!/bin/sh

settings put global airplane_mode_on 0
svc bluetooth enable
svc wifi enable

I had to manually put this into /system/bin after flashing, because I have no idea how to add this to the system.img on build. Then I had to also manually run

 chcon u:object_r:postboot_exec:s0 system/bin/postboot

But after that, it worked! :slight_smile:

Yeah, that’s why I mentioned to pay attention to selinux :wink:

Either approach (exec or service) should work fine as long as you apply the proper context, and putting selinux in permissive, as you found out, doesn’t do the trick. The init process does its own selinux checks just to make sure.

Now you still have a couple of concerns you mentioned;

  1. installation of your shell script to the system partition,
    – create a directory at device/linaro/hikey/yourstuff
    – create an Android.mk in that directory that installs the file where you need it. Look at this one to get the pattern; mali/utgard/Android.mk - device/linaro/hikey - Git at Google
  2. having to run chcon.
    – Edit this file; sepolicy/file_contexts - device/linaro/hikey - Git at Google

@doitright @loic thanks for the help.

Re 1: it’s good to learn how to do that, but since we only have 3 prototypes and just 2 to ship, i might just do it manually.

Re 2: i did that already but it probably didn’t work because the file wasn’t there?

  1. The system partition is read-only, so any selinux context has to be applied to it either during system image generation, or manually.

In the end i used:

# Copy postboot script
PRODUCT_COPY_FILES += \
    device/linaro/hikey/postboot/postboot:$(TARGET_COPY_OUT_SYSTEM)/bin/postboot

which comes down to the same.