Disabling offline charge in Android


Introduction

In this guide we are going to show you how we have made several different Android tablets turn on when connected to power. You might need this behavior if your are installing the tablet as an entertainment system in a car, if you are setting up a tablet to be used in kiosk mode, building a dashboard for your office etc. This is also referred to as disabling offline charging, as the device looses its ability to charge while powered off. Other places this is referred to as “boot on charge”.

I have based this guide on the experiences I have had with achieving this on the following devices

  • Dragontouch x10 Allwinner A83T Running Android 5.0.1
  • Dragontouch x10 Allwinner A83T Running Android 4.4.4
  • Lenovo A10 MT6752 running Android 5.0.1
  • Samsung SMT520 running Android 4.4.2

In my quest to solve this I have stumbled upon guides for the following devices as well.

Booting nexus 7

Part 1 - extract boot partition

When an Android device, that is turned off, is connected to power it begins the boot process by loading, among other things the boot partition and on some Mediatek devices the logo partition. The boot partition is interesting as it contains the init.rc files that describes how to start charging and how to boot the Android system. This partition can also contain graphics for the boot splash image as well as icons used during the charging phase - eg battery level graphics. Take a look at the elinux guide on how Android boots to understand the boot process more thoroughly.

In this guide we are interested in understanding how the Android device boots. This allow us to either fake that the user presses the power button during charge to start the device (Dragontouch with Android 5.0.1), reboot the system when charge begins (Dragon touch 4.4.4) or override system binaries that manages the charge process with scripts that reboots the system.

Reading init.rc files

In order to gain intimate knowledge about how a device boots we need access to the device init.rc files. For some devices you can find the init.rc files in the device root.

[email protected]:/ # ls -la                                                          
drwxr-xr-x root     root              2017-04-21 09:26 acct
drwx------ root     root              1969-12-31 19:00 bootloader
drwxrwx--- system   cache             2017-02-24 07:56 cache
lrwxrwxrwx 400      401               2016-01-15 09:07 charger -> /sbin/healthd
dr-x------ root     root              2017-04-21 09:26 config
-rw-r--r-- 400      401          3944 2016-01-15 09:07 config_mem.ini
lrwxrwxrwx root     root              2017-04-21 09:26 d -> /sys/kernel/debug
drwxrwx--x system   system            2017-02-24 07:57 data
-rw-r--r-- 400      401           281 2016-01-15 09:07 default.prop
drwxr-xr-x root     root              2017-04-21 09:26 dev
-rw-r--r-- 400      401       6040773 2016-01-15 09:07 disp.ko
lrwxrwxrwx root     root              2017-04-21 09:26 etc -> /system/etc
-rw-r--r-- 400      401         12176 2016-01-15 09:07 file_contexts
-rw-r----- 400      401          2326 2016-01-15 09:07 fstab.sun8i
-rwxr-x--- 400      401        387684 2016-01-15 09:07 init
-rwxr-x--- 400      401          2410 2016-01-15 09:07 init.common.rc
-rwxr-x--- 400      401           944 2016-01-15 09:07 init.environ.rc
-rwxr-x--- 400      401         21734 2016-01-15 09:07 init.rc
-rwxr-x--- 400      401           293 2016-01-15 09:07 init.recovery.sun8i.rc
-rwxr-x--- 400      401          1475 2016-01-15 09:07 init.sun8i.common.rc
-rwxr-x--- 400      401          7440 2016-01-15 09:16 init.sun8i.rc
-rwxr-x--- 400      401          3481 2016-01-15 09:07 init.sun8i.usb.rc
-rwxr-x--- 400      401          1927 2016-01-15 09:07 init.trace.rc
-rwxr-x--- 400      401          3885 2016-01-15 09:07 init.usb.rc
-rwxr-x--- 400      401           301 2016-01-15 09:07 init.zygote32.rc
-rwxr-x--- 400      401       4196352 2016-01-15 09:07 initlogo.rle
...

The init.*.rc files are plain text and their naming as well as the init syntax is explained in detail in the Android init language reference

Making changes to init.rc files

However the / directory is readonly and I have been unable to make changes to the files from here.

So in order to make changes to these files we need to extract the boot partition, unpack the ramdisk within, make changes, pack ramdisk and restore boot partition.

Disclaimer. Making changes to the device boot partition is not without risk and surely will break any guarantee! You could end with a bricked device. You might bring the device into a state where it cannot charge. You could get stuck in a boot loop or kill a kitten. This is solely your responsibility.

Create image of boot partition

Use the dd tool to create an image file of the boot partition and save it to a directory that you can access. You can the use adb pull to copy the partition image to your PC

adb shell dd if=<path_to_boot_partition> of=/sdcard/boot.img
adb pull /sdcard/boot.img

The path to the boot partition differs between Android versions, manufacturers etc. In case of dragontouch x10 this should do the trick. You might need SU permissions to run dd

adb shell dd if=/dev/block/by-name/boot of=/sdcard/boot.img
adb pull /sdcard/boot.img

Extract ramdisk

Use Android Kitchen to extract boot.img and ramdisk. I will not describe the process in-depth here as the Android Kitchen interface will guide you through the process. If you cannot extract the boot partion image or ramdisk you might need to find a specific version of Android Kitchen for your tablet. I was unable to extract the ramdisk from Lenovo A10 device with the above mentioned method. To find the right version of Android Kitchen you need the to know the platform/chipset/board name. Use getprop to get this.

[email protected]:/ $ getprop | grep MT
[ro.mediatek.platform]: [MT6752]

Extensive use of Google-Fu got me to “CarlivImageKitchen64” This version has supports the Mediatek board.

Part 2 - modify boot image

The key to enable offline charging is to gain a decent understanding of its init.*.rc files. Take a good look at the Android Init Language Specification

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. It imports /init.${ro.hardware}.rc which is the primary vendor supplied .rc file.

For the devices I have worked with /init.${ro.hardware}.rc was the rc file that contained the code specific for handling charging. When looking at .rc files please keep in mind that Actions and Services can be extended in more specific .rc files. > Actions and Services have unique names. If a second Action is defined with the same name as an existing one, its commands are appended to the commands of the existing action.

Dragon touch x10. Android 5.1

This is specific for Android 5.1 take a look in the section below to see the instructions for Android 4.4.4

When looking through the .rc files on this device i found that the main init.rc contained this interesting action:

# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
class_stop charger
trigger late-init

After the charging process is started a full boot can trigger by running trigger late-init

In the model specific init.sun8i.rc file I found the action where the charge process was started.

on charger
  insmod sunxi_tr.ko
  insmod disp.ko
  class_start charger
  write /sys/module/printk/parameters/console_suspend N
  write /proc/sys/kernel/printk 0

So to make this device start full boot when it starts charging change the on charger action to:

on charger
  insmod sunxi_tr.ko
  insmod disp.ko
  class_start charger
  write /sys/module/printk/parameters/console_suspend N
  write /proc/sys/kernel/printk 0
  class_stop charger
  trigger late-init

I guess that this hack will work for other devices that uses Healthd to manage the charging.

Dragon touch x10. Android 4.4.4

When searching through the .rc files on this version of android there were no hint of triggering a late-init action. I also found that the charger class referenced in the actions was no longer a symlink to Healthd but a binary file. After several failed attempts I succeeded in achieving the offline boot behavior by overriding the charger binary with the following script:

#!/system/bin/sh
/system/bin/reboot

Take note of the permissions for the charger binary, then override the binary file with the script and make sure that it has the same permissions as before.

Part 3 - Pack boot image and override boot partition

Now it’s time to pack everything back up again to check if it is working. Use Android Kitchen to repack the boot image. Make sure that the changes are actually written to the image by extracting the same image again and verifying.

Upload the modified boot.img to the sdcard and override the boot partition on device. Remember to verify the path to the boot partion as it might be different on your device. In case of dragon touch x10 I ran the following commands:

adb push boot.img /sdcard/boot.img
adb shell dd if=/sdcard/boot.img of=/dev/block/by-name/boot
adb shell rm /sdcard/boot.img
adb shell reboot

Using CarlivImageKitchen64 for extracting boot partition

For mediatek(MT6752)

I tried the same procedure for the MT6752 as described in part 1 - 3. However every time I ended stuck just before or after the charging animation was started. I also tried to override the charger link in the root of the ramdisk with a script to rebooting the device - the same way as for Dragon Touch x10 with Android 4.4.4. However this did not seem to make any change to the charge flow

The on charger action in the init.mt6752.rc looks like this:

on charger
  mount ext4 /dev/block/platform/mtk-msdc.0/by-name/system /system ro wait
  start fuelgauged
  start kpoc_charger
  start servicemanager
  # disable USB
  write /sys/devices/platform/mt_usb/cmode 0

The kpoc_charger service is described in the same file:

service kpoc_charger /system/bin/kpoc_charger
  class charge

I found that you can override the kpoc_charger binary just like with Dragon touch x10. Android 4.4.4. kpoc_charger does not reside in the boot partition. It can be found at /system/bin/kpoc_charger. To make changes to files on system you must first mount the system partition as rw using: ` mount -o rw,remount,rw /system`

Then you can override kpoc_charger with:

#!/system/bin/sh
/system/bin/reboot

Remember to change owner and permissions for the file

chown root:shell kpoc_charger
chmod 751 kpoc_charger

This will make the device boot when connected to a charger To override this binary

Improvements

I found that when disabling offline charging you can end up with a completely discharged device that tries to boot every time it is connected to power. As the boot process requires a lot of juice the device cannot boot and the device ends stuck in a boot loop. The simple solution to this was to start the device in fastboot mode. This stopped the boot process and allowed the device to charge. I wanted to avoid this situation in the future so I replaced the simple reboot script with a more sophisticated one that would only reboot the device if the device was decently charged. If not it would run the original charging script which I first renamed. The example below works for the Mediatek(MT6752) device.

#!/system/bin/sh
#Skip offline charge and start device if enough juice on battery. If low on battery do offline charge
CAPACITY=$(cat /sys/class/power_supply/battery/capacity)
MIN_CAPACITY=15
echo $CAPACITY
if [ $((CAPACITY)) -gt $MIN_CAPACITY ]
  then
    /system/bin/reboot
fi
/system/bin/kpoc_charger_orig



By: Tobias Alrøe