Successfully unfucking a fucked partition set in an A/B android device

I own a very nice piece of plastic and chips since the end of 2018. My previous smartphone was a shiny almost-everlasting Nexus 5, that unfortunately fall out of the grace of its creators (google + LG stopped to provide updates a long time ago, but the community of OSS tinkerers maintained an updated version of LineageOS for a while). I bought a OnePlus 6 to replace it, hoping to find a very similar experience: full of support from the LineageOS community and easily rootable.

Turned out I was quite wrong, but the OSS community is not to blame. The main source of pain has come from the new A/B layout of the partitions in android.

TL;DR

Having care of replacing the value for healthy_part with the correct one for your case, use this script from recovery, entering via adb shell

healthy_part="a"
if [[ "$healthy_part" == "a" ]]; then
  broken_part="b";
else
  broken_part="a"
fi
for part in /dev/block/by-name/*_$healthy_part; do
  source=$(readlink -fn $part)
  dest=$(readlink -fn ${part%%_$healthy_part}_$broken_part
  if ! [[ "$dest" == *"/data"* ]]; then
    dd if=$source of=$dest
    echo "done: $source -> $dest"
  fi
done

The long version

Since the beginning, I bought this smartphone with the idea of using it with LineageOS, hoping to easily add a su binary as an easy add-on. This is not the case, if one wants to have a usable phone with banking and identity-sensitive apps. The modernĀ© way to do it is using Magisk. I was also bound to install the google apps (universally called Gapps), because many apps do expect to find such services on the phone and the lovely homebrewed microG project is quite dead.

All this comes to a cost. The process I was supposed to follow is the following:

      1. Unlock the bootloader
      2. Restart into the bootloader (turn off the phone and then start long pressing the power button + volume up button)
      3. Start the phone using a custom recovery (I used TWRP, with<sudo fastboot boot path_to_twrp.img)
      4. Install LineageOS (either sideloading it or pushing it with adb push lineageos.img /sdcard and then using the install menu)
      5. (HERE IS THE IMPORTANT BIT) Reboot to recovery AND install first the Gapps and then Magisk, either by sideload or pushing the zips as the previous point

Why the last step is so important? Because of this A/B layout. The thing is that, when installing the update for the OS (in this case, the lastest LineageOS that replaces OxygenOS), the installer is performed on the inactive partition. Which partition it is, depends on the currently active one. If you are, let’s say, on the A partition when rebooting to bootloader, such is the active partition. In this case, the update will be flashed on the B partition. But we want to install the Gapps and the Magisk magic before the first boot into the new, updated, system. This because both these applications do have some sort of high privilege and make changes to the system partition and, as such, are needed before the first boot of the new OS. But both the Gapps and Magisk installer act on the currently active partition. If we’d install them right after installing the update, we’d be installing them to the A partition, the one that has not been touched by the update!

Flow to upgrade to LineageOS with Gapps and Magisk
Flow to upgrade to LineageOS with Gapps and Magisk

At the end of this process, after the first successful reboot into partition B, the OS updates itself onto A. What bothers me is that I am not aware if this is the case also with the Gapps and Magisk.

Missing flow for Gapps and Magisk
Missing flow for Gapps and Magisk

Useless to say, this is not what I did and I have evidently fucked up at some point in time. After many failed upgrade attempts, with an apparently random failure rate, I got all that I wrote above, and realized that only the A partition set was healthy (because it was the only I was able to upgrade) and that the B was somehow fucked up.

The fix

I remembered that the nice LineageOS people gave the people the possibility to copy all the set of A partitions to the B set. This because, sometimes, the OEM (the phone manufacturer) shipped the handset with only one set of partitions, the A one, clean and working, and to be sure to reach a working state after upgrading to LineageOS, they devised that the right thing was to pour in all the A partitions content into the B ones. I looked into the script and extracted the only part I needed, taking care of avoiding any partition that was not directly mapped to a block device (therefore filtering out the partitions linked to an .img file on the data partition).

I hope you won’t never need it. Nevertheless, if you got here, you’re welcome.