Off-computer updater/flasher for A-only without recovery

How to use:
- Push UNSPARSED system.img to /sdcard
- Create file /cache/phh/flash
- Create block.map:
$ uncrypt /data/media/0/system.img /cache/phh/block.map
- Reboot

This is done by copying /system to a tmpfs, then killing all services,
moving /system to /dev/old-system, unmounting it, then applying
uncrypt's block.map

Tested devices as of today:
- Blackview A20
- Huawei Mate 9
diff --git a/base.mk b/base.mk
index ffa10ac..2007925 100644
--- a/base.mk
+++ b/base.mk
@@ -66,3 +66,8 @@
 PRODUCT_PACKAGES += \
 	bootctl \
 	vintf
+
+PRODUCT_COPY_FILES += \
+	device/phh/treble/twrp/twrp.rc:system/etc/init/twrp.rc \
+	device/phh/treble/twrp/twrp.sh:system/bin/twrp.sh \
+	device/phh/treble/twrp/buysbox-armv7l:system/bin/busybox_phh
diff --git a/twrp/twrp.rc b/twrp/twrp.rc
new file mode 100644
index 0000000..f254786
--- /dev/null
+++ b/twrp/twrp.rc
@@ -0,0 +1,4 @@
+on post-fs
+	exec - root -- /system/bin/vndk-detect
+	export LD_CONFIG_FILE /system/etc/ld.config.${persist.sys.vndk}.txt
+	exec u:r:phhsu_daemon:s0 root -- /system/bin/twrp.sh
diff --git a/twrp/twrp.sh b/twrp/twrp.sh
new file mode 100644
index 0000000..0baf544
--- /dev/null
+++ b/twrp/twrp.sh
@@ -0,0 +1,142 @@
+#!/system/bin/sh
+
+if [ -z "$cache_log" ];then
+	if [ -f /cache/phh/flash ];then
+		rm -f /cache/phh/flash
+	else
+		exit 0
+	fi
+	cache_log=1 exec /system/bin/sh -x "$0" > /cache/phh/logs 2>&1
+fi
+
+#init.rc hooks are based on "0" (non-configfs) or "1" (configfs), so set it to 2 so that noone is triggered
+if [ -z "$nosystem" ];then
+	configfs="$(getprop sys.usb.configfs)"
+	export configfs
+	setprop sys.usb.configfs 2
+	setprop service.adb.tcp.port 5555
+
+	mount -o private,recursive rootfs /
+
+	mkdir /dev/new-system/
+	chmod 0755 /dev/new-system
+	mkdir /dev/old-system
+
+	cp -R --preserve=all /system/lib64 /dev/new-system/lib64
+	cp -R --preserve=all /system/lib /dev/new-system/lib
+	cp -R --preserve=all /system/bin /dev/new-system/bin
+	cp -R --preserve=all /system/xbin /dev/new-system/xbin
+	cp -R --preserve=all /system/etc /dev/new-system/etc
+
+	getprop | \
+	    grep -e restarting -e running | \
+	    sed -nE -e 's/\[([^]]*).*/\1/g'  -e 's/init.svc.(.*)/\1/p' |
+	    while read svc ;do
+		setprop ctl.stop $svc
+	    done
+
+	setenforce 0
+	umount /sbin/adbd
+	mount -o move /system /dev/old-system
+	/dev/new-system/bin/busybox_phh mount -o bind /dev/new-system /system
+	nosystem=1 exec /system/bin/sh -x "$0"
+fi
+
+umount /dev/old-system
+setprop service.adb.root 1
+
+if [ "$configfs" == 1 ];then
+	mount -t configfs none /config
+	rm -Rf /config/usb_gadget
+	mkdir -p /config/usb_gadget/g1
+
+	echo 0x12d1 > /config/usb_gadget/g1/idVendor
+	echo 0x103A > /config/usb_gadget/g1/idProduct
+	mkdir -p /config/usb_gadget/g1/strings/0x409
+	echo phh > /config/usb_gadget/g1/strings/0x409/serialnumber
+	echo phh > /config/usb_gadget/g1/strings/0x409/manufacturer
+	echo phh > /config/usb_gadget/g1/strings/0x409/product
+
+	mkdir /config/usb_gadget/g1/functions/ffs.adb
+	mkdir /config/usb_gadget/g1/functions/mtp.gs0
+	mkdir /config/usb_gadget/g1/functions/ptp.gs1
+
+	mkdir /config/usb_gadget/g1/configs/c.1/
+	mkdir /config/usb_gadget/g1/configs/c.1/strings/0x409
+	echo 'ADB MTP' > /config/usb_gadget/g1/configs/c.1/strings/0x409/configuration
+
+	mkdir /dev/usb-ffs
+	chmod 0770 /dev/usb-ffs
+	chown shell:shell /dev/usb-ffs
+	mkdir /dev/usb-ffs/adb/
+	chmod 0770 /dev/usb-ffs/adb
+	chown shell:shell /dev/usb-ffs/adb
+
+	mount -t functionfs -o uid=2000,gid=2000 adb /dev/usb-ffs/adb
+
+	/dev/new-system/bin/adbd &
+
+	sleep 1
+	echo none > /config/usb_gadget/g1/UDC
+	ln -s /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/c.1/f1
+	echo ff100000.dwc3 > /config/usb_gadget/g1/UDC
+
+	sleep 2
+	echo 2 > /sys/devices/virtual/android_usb/android0/port_mode
+else
+	mkdir /dev/usb-ffs
+	chmod 0770 /dev/usb-ffs
+	chown shell:shell /dev/usb-ffs
+	mkdir /dev/usb-ffs/adb/
+	chmod 0770 /dev/usb-ffs/adb
+	chown shell:shell /dev/usb-ffs/adb
+
+	mount -t functionfs -o uid=2000,gid=2000 adb /dev/usb-ffs/adb
+	echo adb > /sys/class/android_usb/android0/f_ffs/aliases
+	setprop sys.usb.config adb
+
+	echo 0 > /sys/class/android_usb/android0/enable
+	echo 18d1 > /sys/class/android_usb/android0/idVendor
+	echo 4EE7 > /sys/class/android_usb/android0/idProduct 4EE7
+	echo adb > /sys/class/android_usb/android0/functions
+	getprop ro.boot.serialno |tr -d '\n' |cat > /sys/class/android_usb/android0/iSerial
+	echo phh > /sys/class/android_usb/android0/iManufacturer
+	echo phh > /sys/class/android_usb/android0/iProduct
+	echo 1 > /sys/class/android_usb/android0/enable
+
+	/dev/new-system/bin/adbd &
+fi
+
+
+death() {
+	sleep 180
+	reboot
+}
+
+dev="$(sed -n 1p /cache/phh/block.map)"
+                    devbase="$(echo $dev | sed -nE 's;(/dev/block/.*/)userdata;\1;p')"
+[ -z "$devbase" ] && devbase="$(echo $dev | sed -nE 's;(/dev/block/.*/)data;\1;p')"
+for i in system system_a;do
+	v="$devbase/$i"
+	[ -b "$v" ] && system="$v"
+done
+#Failed...
+[ -z "$system" ] && death
+
+blockdev --setrw "$system"
+
+size="$(sed -En '2s/^([0-9]+) .*/\1/p' /cache/phh/block.map)"
+block_size="$(sed -En '2s/.* ([0-9]*)$/\1/p' /cache/phh/block.map)"
+n_ranges="$(sed -n 3p /cache/phh/block.map)"
+block_id=0
+for i in $(seq 1 $n_ranges);do
+	range_start="$(sed -En $((i+3))'s/^([0-9]+) .*/\1/p' /cache/phh/block.map)"
+	range_end="$(sed -En $((i+3))'s/^.* ([0-9]+)$/\1/p' /cache/phh/block.map)"
+	n_blocks=$((range_end-range_start))
+	busybox_phh dd bs=$block_size skip=$range_start seek=$block_id count=$n_blocks if=$dev of=$system
+
+	block_id=$((block_id+n_blocks))
+done
+
+sync
+reboot