[ASUS ZenFone 8] bnsmb:
How to trigger an action when a property is changed

In Android it's possible to trigger various actions by changing the value of a property.

This feature is quite handy and the implementation using Magisk is not really difficult.

As an example:

In the original Android from ASUS for the Zenfone 8 you can disable and enable the swap on a ZRAM device by changing the value for the property vendor.zram.enable:

e.g.:

To turn the swap on use

setprop vendor.zram.enable 1

and to turn the swap off use

setprop vendor.zram.enable 0

To get the current value use

getprop vendor.zram.enable

or

check the output of the OS command free.

(see How to disable or change the swap device in the Android 12 from ASUS for the Zenfone 8 for details)

This feature is not implemented in the OmniROM for the ASUS Zenfone 8 but quite useful so let's see how to implement it in the OmniROM.

The Triggers and Action for this Android feature are configured in the init.rc files in the root filesystem for the OS (see https://android.googlesource.com/platform/system/core/+/master/init/README.md for details). The root filesystem for Android is read-only mounted so without creating your own Android OS image for the phone it's not possible to add the functionality to the OS.

But we can use the Root Directory Overlay System from Magisk (see https://github.com/topjohnwu/Magisk/blob/master/docs/guides.md for the documentation) to implement it.

The detailed process for creating additional *.rc files for Android via Magisk is described here:

How to run a script at shutdown

Therefore I will not go into the details here. But please read that post before you continue

First we check how this feature is implemented in the Original Android for the Zenfone:

Enabling and disabling the swap device on ZRAM is configured in the .rc file

/vendor/etc/hw/init.asus.debugtool.rc

using these settings in the original Android OS for the Zenfone 8:

service asus_zram /system/vendor/bin/sh /vendor/bin/init.asus.zram.sh
user root
group root
disabled
seclabel u:r:vendor_qti_init_shell:s0
oneshot

on property:persist.vendor.zram.enable=1
setprop vendor.zram.enable "1"
setprop vendor.zram.disksize ${persist.vendor.zram.disksize}

on property:persist.vendor.zram.enable=0
setprop vendor.zram.enable "0"
setprop vendor.zram.disksize ${persist.vendor.zram.disksize}

on property:vendor.zram.enable=*
start asus_zram

The script used to enable or disable the swap device on ZRAM in the original Android for the Zenfone 8 is:

/vendor/bin/init.asus.zram.sh

The script is quite simple (see also below):

It uses two properties to configure the swap device:

vendor.zram.enable : if this property is set to 1 the script enables the swap device and if the property is set to 0 it disables the swap device

vendor.zram.disksize : the value of this property is the size of the ramdisk.

Now we can implement this feature for the OmniROM:

Note:

All commands must be done as user root in a shell on the phone or in an adb shell

First we check the prerequisites for the feature:

The used shell for the service exists in the OmniROM:

root@ASUS_I006D:/data/adb/workdir # ls -Zl /vendor/bin/sh
-rwxr-xr-x 1 root shell u:object_r:vendor_shell_exec:s0 318216 2009-01-01 01:00 /vendor/bin/sh
root@ASUS_I006D:/data/adb/workdir #

The script to toggle the ramdisk on the swap device also already exists in the OmniROM:

root@ASUS_I006D:/data/adb/test # ls -l /vendor/bin/init.asus.zram.sh
-rwxr-xr-x 1 root shell 1127 2009-01-01 01:00 /vendor/bin/init.asus.zram.sh
root@ASUS_I006D:/data/adb/test #

And the necessary SELinux contexts are also already defined in the OmniROM.

So, let's start:

# create a temporary directory
#
mkdir /data/adb/workdir
cd /data/adb/workdir

# create the additional .rc file
#
cat >init.asus.zram.rc <<-\EOT
#
# Note:
#
# The service definition for an OS without the script init.asus.zram.sh should be
#
# service asus_zram /system/bin/sh /system/sbin/init.asus.zram.sh
#
service asus_zram /system/vendor/bin/sh /vendor/bin/init.asus.zram.sh
user root
group root
disabled
seclabel u:r:vendor_qti_init_shell:s0
oneshot
#
# these properties can be used to define the initial state of the ramdisk on ZRAM
#
on property:persist.vendor.zram.enable=1
setprop vendor.zram.enable "1"
setprop vendor.zram.disksize ${persist.vendor.zram.disksize}

on property:persist.vendor.zram.enable=0
setprop vendor.zram.enable "0"
setprop vendor.zram.disksize ${persist.vendor.zram.disksize}

on property:vendor.zram.enable=*
start asus_zram

# The property persist.vendor.zram.enable is not defined in the OmniROM. If necessary you can add another triger in the .rc file,
# e.g to enable the swap device by default use
#
on early-init
setprop persist.vendor.zram.enable 1
EOT

# get the current active slot
#
CURRENT_SLOT=$( getprop ro.boot.slot_suffix )
echo "The current active slot is: ${CURRENT_SLOT}"

# copy the boot partition from the active slot to a file

dd if=/dev/block/by-name/boot${CURRENT_SLOT} of=./boot_root.img

# unpack the image file

/data/adb/magisk/magiskboot unpack ./boot_root.img

# add the new dir and file to the ramdisk from the boot partition

/data/adb/magisk/magiskboot cpio ramdisk.cpio \
"mkdir 0700 overlay.d" \
"add 0700 overlay.d/init.custom.rc init.asus.zram.rc"

# recreate the image file for the boot partition

/data/adb/magisk/magiskboot repack boot_root.img

# write the corrected image file to the boot partition

dd if=./new-boot.img of=/dev/block/by-name/boot${CURRENT_SLOT}

That's it.

After the next reboot switching the ramdisk on the ZRAM device via an property should be active:

root@ASUS_I006D:/ # reboot

# .....
# start a new adb session
# ....

shell@ASUS_I006D:/ $ getprop ro.omni.version
12-20220703-zenfone8-MICROG

#
# Note: The property is only visible to the user root
#
shell@ASUS_I006D:/ $ su -

root@ASUS_I006D:/ # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:magisk:s0
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # free
total used free shared buffers
Mem: 7612493824 4835229696 2777264128 14585856 14487552
-/+ buffers/cache: 4820742144 2791751680
Swap: 4294963200 0 4294963200
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # getprop vendor.zram.enable
1
root@ASUS_I006D:/ #

# -> now disable the swap on ZRAM

root@ASUS_I006D:/ # setprop vendor.zram.enable 0
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # getprop vendor.zram.enable
0
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # free
total used free shared buffers
Mem: 7612493824 4840824832 2771668992 14524416 14483456
-/+ buffers/cache: 4826341376 2786152448
Swap: 0 0 0
root@ASUS_I006D:/ #

# -> now enable the swap on ZRAM again

root@ASUS_I006D:/ # setprop vendor.zram.enable 1
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # getprop vendor.zram.enable
1
root@ASUS_I006D:/ #

root@ASUS_I006D:/ # free
total used free shared buffers
Mem: 7612493824 4844777472 2767716352 14524416 14512128
-/+ buffers/cache: 4830265344 2782228480
Swap: 4294963200 0 4294963200
root@ASUS_I006D:/ #

Workarounds for other configuration

Find below some workarounds for OS versions without the prerequisites for implementing this feature.

1. The script to toggle the swap /vendor/bin/init.asus.zram.sh does not exist

If the script /vendor/bin/init.asus.zram.sh does not exist in your OS create a Magisk Module for the script

To create a (dummy) Magisk Module for the script do:

mkdir -p /data/adb/modules/toggle_ram/system/bin

#
# create the script to toggle the ramdisk on ZRAM
#
cat >/data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh <<-\EOT

lahaina_set=`getprop vendor.asus.zram_setting`
if test "$lahaina_set" != "1"; then
echo "[asus_zram] init.kernel.post_boot-lahaina.sh not finished yet!"> /dev/kmsg
exit 0
fi
disksize=`getprop vendor.zram.disksize`
zram_enable=`getprop vendor.zram.enable`

MemTotalStr=`cat /proc/meminfo | grep MemTotal`
MemTotal=${MemTotalStr:16:8}
let RamSizeGB="( $MemTotal / 1048576 ) + 1"

if test "$disksize" = ""; then
disksize="4096M"
fi
echo "[asus_zram]RamSizeGB=${RamSizeGB}" > /dev/kmsg
if test "$zram_enable" = "1"; then
if [ $RamSizeGB -le 7 ]; then #this is for 6G; or the value will be 4G(8G,12G,16G,18G,etc)
disksize="( $RamSizeGB * 1024 ) / 2""M"
fi
swapoff /dev/block/zram0 2>/dev/kmsg
echo 1 > sys/block/zram0/reset 2>/dev/kmsg
sleep 1
echo lz4 > /sys/block/zram0/comp_algorithm
echo $disksize > /sys/block/zram0/disksize 2>/dev/kmsg
mkswap /dev/block/zram0 2>/dev/kmsg
swapon /dev/block/zram0 -p 32758 2>/dev/kmsg
echo "[asus_zram]write zram disksize=${disksize}" > /dev/kmsg
fi
if test "$zram_enable" = "0"; then
swapoff /dev/block/zram0 2>/dev/kmsg
echo "[asus_zram]turn off the zram" > /dev/kmsg
fi
EOT

chmod 755 /data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh

chown root:shell /data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh

chcon u:object_r:vendor_file:s0 /data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh

Check the result:

root@ASUS_I006D:/ # ls -lZ /data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh
-rwxr-xr-x 1 root shell u:object_r:vendor_file:s0 1109 2022-10-03 21:14 /data/adb/modules/toggle_ram/system/bin/init.asus.zram.sh
root@ASUS_I006D:/ #

Then change the script to execute in the service definition in the .rc file to /system/bin/init.asus.zram.sh:

service asus_zram /system/vendor/bin/sh /system/bin/init.asus.zram.sh

The rest of the instructions can be be used without changes.

2. The binary /system/vendor/bin/sh does not exist

If the shell /system/vendor/bin/sh does not exist in the OS create an Magisk Module with an approbiate shell:

Note:

The shell /system/bin/sh can not be used because it's configured with another SELinux context:

root@ASUS_I006D:/ # ls -lZ /system/vendor/bin/sh
-rwxr-xr-x 1 root shell u:object_r:vendor_shell_exec:s0 318216 2009-01-01 01:00 /system/vendor/bin/sh
root@ASUS_I006D:/ #

# but

root@ASUS_I006D:/data/adb/workdir # ls -Zl /system/bin/sh
-rwxr-xr-x 1 root shell u:object_r:shell_exec:s0 307768 2009-01-01 01:00 /system/bin/sh
root@ASUS_I006D:/data/adb/workdir #

To create a (dummy) Magisk Module for the necessary shell do:

mkdir -p /data/adb/modules/vendorshell/system/bin
cp /system/bin/sh /data/adb/modules/vendorshell/system/bin/sh
chcon u:object_r:vendor_shell_exec:s0 /data/adb/modules/vendorshell/system/bin/vendor_sh

Check the result:

root@ASUS_I006D:/data/adb/workdir # ls -lZ /data/adb/modules/vendorshell/system/bin/vendor_sh
-rwxr-xr-x 1 root root u:object_r:vendor_shell_exec:s0 307768 2022-10-03 20:41 /data/adb/modules/vendorshell/system/bin/vendor_sh
root@ASUS_I006D:/data/adb/workdir #

Now change the shell in the service definition in the .rc file to /system/bin/vendor_sh:

service asus_zram /system/bin/vendor_sh /vendor/bin/init.asus.zram.sh

The rest of the instructions can be be used without changes.

3. The necessary shell /system/vendor/bin/sh and the script /vendor/bin/init.asus.zram.sh do both not exist

If the necessary shell /system/vendor/bin/sh and the script /vendor/bin/init.asus.zram.sh do not exist you can also create one (dummy) Magisk module for both.

See

https://topjohnwu.github.io/Magisk/guides.html

and

Some hints for using Magisk on Android phones

for instructions and infos about how to create a real Magisk Module

4. Missing SELinux contexts

These instructions assume that all necessary SELinux contexts are already defined in the used OS.

If there are SELinux contexts missing it might not work without adding the missing SELinux contexts

(that might be difficult and I must admit that I did not test that)

5. only for the records:

The magiskboot command can also be used to add new files to the /sbin directory in the root filesystem.

This can be can be configured like this:

/data/adb/magisk/magiskboot cpio ramdisk.cpio \
"mkdir 0700 overlay.d" \
"add 0700 overlay.d/init.custom.rc init.asus.zram.rc" \
"mkdir 0700 overlay.d/sbin" \
"add 0700 overlay.d/sbin/my_new_script.sh my_script.sh"

This is useful for adding binaries or scripts for actions that should be executed while the other partitions are not yet mounted and therefor the files in these filesystems not yet available. But for the action defined in this post this is not necessary.

And be aware that the files added to the root filesystem ( /sbin/my_new_script.sh in this example) is only available while booting the phone.

6. Other problems

In case of problems please check the post

How to run a script at shutdown

again.

Also check the restrictions for this approach documented in that post

History

06.10.2022 /bs

corrected some typos