-
Notifications
You must be signed in to change notification settings - Fork 465
[mbtool] ROM installer
The base ROM installation code is handled in mbtool/installer.cpp. The mb::Installer
class handles the chroot creation, filesystem mounting, update-binary
execution, and logging. Subclasses of mb::Installer
supply the input (target device, target ROM ID, input zip file, etc.) and a method of output (eg. write to TWRP's file descriptor using ui_print
commands or simply dumping to stdout). Subclasses are able to hook into each of the stages described below.
The installer goes through several stages as described below:
-
Initialization
The installer first scans the input zip file for files named
system.transfer.list
,system.new.dat
, andsystem.img
. If any of those files exist, the zip is determined to contain a system image, which will affect the behavior of later stages.Subclasses can implement
mb::Installer::on_initialize()
to hook into this stage. -
Create chroot
The
/system
,/cache
, and/data
partitions will first be mounted. This is done my simply running themount
command (eg.mount /system
), so the host system is responsible for parsing the fstab file to correctly mount the partitions./proc/mounts
will be read to verify that the partitions were indeed mounted.The installer will then attempt to create the chroot at
/chroot
. If a prior installation failed and left stale mounts or leftover files, they will be unmounted or removed before the installation continues. If unmounting the old mount points fails, the installation will fail to prevent data loss.The following paths are then created in the chroot:
Directories:
-
/mb/
- Temporary multiboot files -
/dev/
- Block, character, and other special devices -
/etc/
- Contains fstab file in TWRP/CWM. Mostly unused. -
/proc/
- (Standard procfs directory) -
/sbin/
- Usually contains programs in the ramdisk -
/sys/
- (Standard sysfs directory) -
/tmp/
- Temporary directory. Unused by mbtool. Possibly used by ROM's installer -
/system/
- Mount point for target system directory -
/cache/
- Mount point for target cache directory -
/data/
- Mount point for target data directory
Mounts:
- '/dev/ (tmpfs)`
/dev/pts/ (devpts)
/proc/ (proc)
/sbin/ (tmpfs)
/sys/ (sysfs)
/tmp/ (tmpfs)
Special files:
/dev/console (maj=5, min=1)
/dev/null (maj=1, min=3)
/dev/ptmx (maj=5, min=2)
/dev/random (maj=1, min=8)
/dev/tty (maj=5, min=0)
/dev/urandom (maj=1, min=9)
/dev/zero (maj=1, min=5)
/dev/loop-control (maj=10, min=237)
Copied:
- Host's
/sbin/
-> chroot's/sbin/
- Host's
/dev/input/
-> chroot's/dev/input/
(Required for AROMA) - Host's
/dev/graphics/
-> chroot's/dev/graphics/
(Required for AROMA)
Subclasses can implement
mb::Installer::on_created_chroot()
to hook into this stage. -
-
Set up environment
The temporary directory (usually
/multiboot/
) will be deleted to prevent issues. The multiboot files below are extracted from the patched zip.-
META-INF/com/google/android/update-binary.orig
-><temp dir>/updater
- The ROM's original update-binary file -
multiboot/bb-wrapper.sh
-><temp dir>/bb-wrapper.sh
- A wrapper around busybox to prevent themount
,umount
, andreboot
commands from being run inside the chroot -
multiboot/info.prop
-><temp dir>/info.prop
- Properties file containing various settings for the installer, such as the target device and ROM ID
This stage cannot be hooked by subclasses.
-
-
Check device
This stage will perform several actions related to the target device:
- Verify that
mbtool.installer.device
ininfo.prop
matches one of the following properties (unlessmbtool.installer.ignore-codename
is set to true, in which case the check will be skipped)ro.product.device
ro.build.product
ro.patcher.device
- Copy boot partition block devices to chroot (as specified in libmbp via
Device::setBootBlockDevs()
) - Copy recovery partition block devices to chroot (as specified in libmbp via
Device::setRecoveryBlockDevs()
) - Copy extra partition block devices to chroot (as specified in libmbp via
Device::setExtraBlockDevs()
)
Subclasses can implement
mb::Installer::on_checked_device()
to hook into this stage. - Verify that
-
Get install type
This stage gathers various information regarding the target ROM ID. It first calls
mb::Installer::get_install_type()
, which must be implemented by subclasses. If the ROM ID is valid, then amb::Rom
object will be created. Otherwise, the installation will fail.This stage cannot be hooked by subclasses.
-
Set up chroot
In this stage, the installer will calculate the SHA1 hash of the boot partition. This is used at the end of the installation to determine if the boot image needs to be modified. The boot partition will also be copied to
<temp dir>/boot.orig
, which is restored if the installation fails. The busybox wrapper is also set up in this stage.The following operations are now performed in the chroot:
- Move
/sbin/busybox
to/sbin/busybox.orig
- Copy busybox wrapper to
/sbin/busybox
- Copy mbtool to
/update-binary-tool
- Copy host's
/default.prop
to chroot's/default.prop
- Copy host's
/file_contexts
to chroot's/file_contexts
Subclasses can implement
mb::Installer::on_set_up_chroot()
to hook into this stage. - Move
-
Mount filesystems
In this stage, the
/system
,/cache
, and/data
directories for the target ROM will be mounted. If the target system, cache, or data paths are images, they will be created as follows:- System image: Size of actual device's
/system
partition (Used byextsd-slot-*
) - Cache image: 4 * 1024 * 1024 * 1024 bytes (4 GiB) (Not used by any install target)
- Data image: 4 * 1024 * 1024 * 1024 bytes (4 GiB) (Not used by any install target)
If the target system path is an image, then the image file will be bind mounted to
/mb/system.img
in the chroot. This is necessary for ROMs that flash system images instead of copying files.No further operations occur if a system image is used. If the system path is a directory, then multiple actions could occur:
- If installing to non-
primary
and the zip contains no system image, then the system path is simply bind mounted to/system
in the chroot - If install to
primary
or the zip contains a system image, then a temporary image is created at/data/.system.img.tmp
(or<external SD>/.system.img.tmp
if space is insufficient) and the contents of the system path are copied into the image. The temporary image is then bind mounted into/mb/system.img
in the chroot.
Subclasses can implement
mb::Installer::on_mounted_filesystems()
to hook into this stage. - System image: Size of actual device's
-
Installation
This stage handles the actual installation of the ROM. The original update-binary (
<temp dir>/updater
) will be bind mounted to/mb/updater
in the chroot and the zip file will also be bind mounted in the chroot (/mb/install.zip
). The update-binary will be searched for several strings to determine if it's likely an AROMA installer. If it is, thenSIGSTOP
will be sent to the parent process to prevent the recovery interface from fighting over the framebuffer. (SIGCONT
will be sent after installation.)Subclasses can implement
mb::Installer::get_properties()
to provide a set of properties that will be available in the installation environment (eg. viagetprop()
in the updater-script). The subclass can also specify whether the passthrough setting. If passthrough is enabled, the subclass will provide a file descriptor that is passed to the updater binary as the second argument. This is what the recovery does when it flashes a zip. The file descriptor allows the ROM installer to display messages on screen (among other things). If the passthrough option is disabled, mbtool will create a pipe, pass it to the ROM installer, and will parse and process all of the data. Note that mbtool will discard all messages besidesui_print
.The following command will then be executed to start the ROM's installer:
/mb/updater <interface> <output fd> </path/to/zip>
Subclasses can implement
mb::Installer::on_pre_install()
to hook into this stage before the installation. Subclasses can implementmb::Installer::on_post_install()
to hook into this stage after the installation. -
Unmount filesystems
/system
,/cache
, and/data
in the chroot will be unmounted. If the system path is an image file, the installer will rune2fsck
to repair the filesystem (if corrupted). If the system path is a temporary image file, the contents will be copied back to the appropriate system directory.Subclasses can implement
mb::Installer::on_unmounted_filesystems()
to hook into this stage. -
Completion
The SHA1 hash of the boot partition will be calculated and compared to the previous hash. If they are not equal, a new file, /romid
, containing the ROM ID string, will be added to the ramdisk. If /default.prop
exists in the ramdisk, the property ro.patcher.device=<target device>
will be appended to the end of the file. If the boot image had any hacks or workarounds for locked bootloaders that are supported by libmbp (eg. loki, bump), they will be reapplied.
Afterwards, the 'good' copy of the boot image will be saved in /sdcard/MultiBoot/<ROM ID>/boot.img
and the SHA512 hash of it added to /data/multiboot/checksums.prop
. The permissions, ownership, and SELinux label on /sdcard/MultiBoot
will be recursively set such that they match /data/media/0
.
Subclasses can implement mb::Installer::on_finished()
to hook into this stage.
- Cleanup
This stage is always called regardless if the installation succeeds or fails. If the installation fails, the backup copy of the boot partition will be restored. If a temporary system image was created, it will be removed. All mount points in the chroot will be unmounted and the directory will be deleted (unless a filesystem could not be unmounted).
Subclasses can implement mb::Installer::on_cleanup()
to hook into this stage.
Unfortunately, installation issues will inevitably occur. mbtool provides a few methods to make debugging issues easier.
If the device's recovery does not log stdout/stderr when flashing zips, it is possible to run mbtool manually through adb. First, reboot to recovery, and then run the following commands:
adb push /path/to/mbtool_recovery /tmp/updater
adb shell chmod 755 /tmp/updater
adb shell /tmp/updater 3 1 /sdcard/example_rom_data-slot-blah.zip
In mbtool/installer.cpp
, change the following defines to 1
:
#define DEBUG_PRE_SHELL 1
#define DEBUG_POST_SHELL 1
When running the installation manually via the command line as shown above, a shell will be launched from inside the chroot immediately before and after the installation. Exiting the shell causes the installation to proceed.
mbtool also allows the installer to be run under a wrapper program, such as strace or valgrind. To do so, set DEBUG_USE_UPDATER_WRAPPER
to 1
in mbtool/installer.cpp
and set the path and arguments accordingly.
// Use a wrapper around the updater
#define DEBUG_USE_UPDATER_WRAPPER 1
#define DEBUG_UPDATER_WRAPPER_PATH "/tmp/strace_static"
//#define DEBUG_UPDATER_WRAPPER_ARGS "-f" // Comma-separated strings