Android on Chrome OS rooting shell scripts

Tested on Chrome OS v. 54-72


NOTE (Nov '18): 


The scripts have been updated (to version 0.27) to address a few recent minor changes in Chrome OS.

 If anyone is experiencing issues (such as unable to write to /system) on recent Chrome OS versions, even after trying the latest version of the script, I'd appreciate it if you leave a comment on the blog, or on this related issue report on github, noting your device model and Chrome OS version.

PREREQUISITES:


A Chromebook with storage space for a ~2GB file in /usr/local/. Exact space usage varies depending on device, but will usually be at least 1.3 GB.

The Chrome OS system partition needs to have been made writable. 
A straightforward way to enable this is usually to enter the following command in the shell, then reboot:
sudo /usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification --partitions $(( $(rootdev -s | sed -r 's/.*(.)$/\1/') - 1))


INSTRUCTIONS:


I recommend trying the latest combined script first, which will attempt to auto-download and extract the required files. 

The combined script may be run by copy/pasting the following into the Chrome OS shell prompt:

curl -Ls https://raw.githubusercontent.com/nolirium/aroc/onescript/RootandSEpatch.sh | sudo sh


Once the script has finished, check its output for any error messages and - assuming success - after a reboot, the Android subsystem should be rooted and fully working.

If any errors are experienced with the combined script, the following method may be tried:

1. Manually download the SuperSU 2.82-SR5 zip 

2. Extract/copy the folders from inside the SuperSU zip to 'Downloads'

3. Run the script(s) - either the combined version (above) which is recommended, or the more widely tested version with separate scripts to root and patch SE Linux (a little further down the page).

IMPORTANT: If you powerwash after running the scripts (without also updating the OS), the Play Store/Android apps may no longer work. If you experience this, the easiest way to fix it is usually to restore the original Android system image by running the following command (then rebooting):


sudo mv /opt/google/containers/android/system.raw.img.bk /opt/google/containers/android/system.raw.img

The combined script, after creating a writable ext4 container and adding SuperSU, attempts to bind mount certain directories within the Android container in order to patch the SE Linux policy file without having to reboot first. In case of any problem with this, the rooting and SE Linux patching scripts may be ran one by one, by pasting the following two commands in the Chrome OS shell. With this method, a reboot is required after running the first script, and again after running the second.

The command to run script 1:

curl -Ls https://raw.githubusercontent.com/nolirium/aroc/master/01Root.sh | sudo sh

The command to run script 2:

curl -Ls https://raw.githubusercontent.com/nolirium/aroc/master/02SEPatch.sh | sudo sh


DESCRIPTIONS:


RootandSEPatch.sh 


Combines the actions from the two scripts listed below, by completing the actions of the first script, then bind mounting files from SuperSU to a location on the (unrooted) container's $PATH, thus being able to patch the SE Linux policy file (the second script) without having to reboot first.


01Root.sh


Creates & formats a ~2GB sparse filesystem image in /usr/local/Android_Images, and copies Android system files therein. Modifies Chrome OS system files: either /usr/share/arc-setup/config.json, /etc/init/arc-setup-env or /etc/init/arc-system-mount.conf and /etc/init/arc-setup.conf (as per CrOS version) - changing the ro.debuggable and mount-as-read-only flags. Renames the original Android filesystem image to *.bk & replaces it with a symlink to the newly-created image. Mounts the newly created image to a folder, and copies SuperSU files to the mounted image as specified in the SuperSU update-binary. Copies BusyBox to the mounted image and installs its symlinks in the Android system/xbin directory.

02SEpatch.sh


Copies an SELinux policy file found at /etc/selinux/arc/policy/policy.30 to the Downloads folder, opens an Android root shell for the SuperSU policy patching command to be entered, then copies the patched policy back to the original location.Backup copies of the original policy.30 are saved at /etc/selinux/arc/policy/policy.30.old and /usr/local/Backup/policy.30.old.

Unroot.sh


If a backup Android image is present in the original location, removes the symlink and restores the backup. Failing this, if a backup is present in in 'Downloads', replaces the modified image with the backup. Attempts to revert the debuggable and mount-as-read-only flags to their original state.

Tested with SuperSU 2.79 & 2.82



KNOWN ISSUES:

  • There is an issue with certain recent Chrome OS versions wherein the Android root filesystem can only be mounted as read-only at runtime. This first occurred on CrOS versions 65. In CrOS versions 68-70, it appears to be necessary to change a line in Android's init.rc in order to enable the expected behaviour (allowing writing to /system in Android, once the relevant environment variable string has been set).
  • After rooting with this script, certain non English fonts may no longer display properly in Android apps. This can be fixed/worked around by copying the relevant NotoSans fonts over from Chrome OS to Android's /system/fonts/chromeos folder. Further details can be found at this issue report on github. If this affects you, feel free to leave a comment below,  (This appears to no longer be an issue on Chrome OS version 66 and newer).
  • At present, updates to Chrome OS will usually overwrite any rootfs customizations, including those carried out by this script. In theory it is possible to keep a watcher script running which, when an OS update is detected, can re-apply the customizations to the updated partition. In practice there are certain issues with this (for instance, if the background script detects that an update has been downloaded and proceeds to re-root the updated Android system, Android apps will stop working until the system has been rebooted). In addition, the OS seems to be subject to constant development and improvement, hence there is no guarantee that what works now will continue to work in future. If anyone has any thoughts to share regarding this topic, feel free to comment below.
  • The current version of the script replaces the original Android system image with a symlink. In order to revert to the original (unrooted) image if required, it will be necessary to either manually restore the backup (easiest),  force an update e.g. with a channel change, or restore from USB.
  • After a powerwash, modified system files may remain modified, and /usr/local may be empty. Again, either manually restoring the backup image, channel changing, or restoring from USB will be necessary in order to have a functioning Android subsystem.
  • Updating the su binary from within the SuperSU GUI app may not work.
  • Stability may be an issue. This remains to be seen. A few OS crashes have been noted. Likely unrelated, though - it seems to crash occasionally in any case (Dev/Canary channels).
  • The modified system image takes up a fair amount of space in /usr/local/. Storing the image in certain other places doesn't seem to work, probably due to mount timings.

PARTIAL CHANGELOG:


v 0.27 - Modified rootfs writable check, which broke due to a CrOS change. Add check if writable container and debug flags are in "/usr/share/arc-setup/config.json" Added fix for ro system in init.rc (substituted '|mount rootfs rootfs / remount bind rw' for '|mount rootfs rootfs / remount bind ro').

v 0.26 - Fixed adding BusyBox to Android system/xbin. Changed SuperSU version used from 2.82SR3 to 2.82SR5. Removed duplicate function in combined script. 

v 0.25 - Rooted container is now a sparse file, which takes up only as much disk space as is necessary. (thanks @hall757 on GitHub for suggesting this). Minor tidying up of combined script. 

v 0.24 - Combined scripts 01Root and 02SEpatch into a single script. 

v 0.23 - Minor changes to support CrOS v62. Patched SE Linux policy is now also copied to /sepolicy inside the Android container, SuperSU apk is now installed in /system/priv-app in the container, and font sharing between Chrome OS and Android is disabled in CrOS in /etc/init/arc-setup-env.  

v 0.22 - Unified arm and Intel versions into a single script. Added functionality to auto-download /extract required files. Removed necessity for additional user interaction in script 2.

v 0.21 - Fixed context of init daemon to properly support launching at boot.

v 0.20 - Added support for 7.1.1 Nougat. Daemon now launched as init service rather than app_process hijack.

v 0.19 - Added support for /etc/init/arc-setup-env (present in latest Canary). Added info for patching SELinux policy with SuperSU 2.8x (--sdk=xx)

v 0.18 - Added support for Chrome v. 59/60 (changed mounting method to mount via symlink. Fixed backing-up of original image file. Added search for extra backup image paths (e.g. when re-running script). 

Making SD card content accessible to Android on Chrome OS with bind mounts

At present, SD card content is not fully accessible to the Android container on Chrome OS.

I wanted to play my PSP games on the go, but the built-in storage on the Asus Flip C100PA is rather meagre (16GB). So, as a temporary workaround I did the following:

  1. Created a new folder named "Bound" in "Downloads".
  2. Created a folder named "PSP_Backups" on my 64 GB SD card (named "UNTITLED").
  3. Plugged in a USB HD and copied all my PSP backup games (.cso files) to the folder on the SD card.
  4. Opened a root shell and entered:
mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/default/emulated/0/Download/Bound && mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/read/emulated/0/Download/Bound && mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/write/emulated/0/Download/Bound
(Which is the following three commands strung into one with &&):

mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/default/emulated/0/Download/Bound
mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/read/emulated/0/Download/Bound
mount -o bind /media/removable/UNTITLED/PSP_Backups /run/arc/sdcard/write/emulated/0/Download/Bound


This gave Android apps read access to the folder. (at least, those I've tried).

An potential issue with bind mounting the card like this is that Chrome OS by default apparently seems to unmount the SD card during deep sleep. So the mounted folders might stop working necessitating a reboot and repeat of the procedure.

This seems to have been fixed by switching off idle suspend as per the following (from https://github.com/dnschneid/crouton/wiki/Power-manager-overrides). 

sudo su                                                                        #cant sudo next command
echo 1 >/var/lib/power_manager/disable_idle_suspend                            #change the action to do nothing
chown power:power /var/lib/power_manager/disable_idle_suspend                  #it belongs to power
restart powerd                                                                 #let the change take effect
exit  
An alternative option might be to temporarily disable the power manager.

Perhaps more complete SD card access integration will be added with an update to Chrome OS  soon, rendering this unnecessary. 

A different method of mounting the SD card to make it available for Android apps is detailed here. It enables write access, and is automated at boot, but does involve modifying a Chrome OS system file - which could potentially crash your computer. Only for the brave (or foolhardy).

UPDATE:  I've also found another, similar method which seems to work on all devices tested. If you have already tried the bind mount method, without success, with an ext* formatted card - please see my most recent comment at the bottom of this page for an alternative.