Android's partitions typically reside on non-volatile NAND memory on a special device or set of devices on the phone. I will be doing a raw byte-level copy of these partitions, which are exposed through special files in /dev/mtd. The mtd bit stands for "Memory Technology Device," and was added to the Linux kernel as an abstraction layer between the Linux block and character device layer and flash hardware.
Why an abstraction layer? Well, NAND flash memory has somewhat idiosyncratic characteristics on the low level, most notably that ones cannot be written to a block. Strange, I know, but bear with me. When you write data to a regular disk, such as a hard drive, you can tell a byte to become set to whatever value you like. Flash doesn't support writes so much as it supports "programming." When you erase a block of flash, its bits all get set to one, and when you write you just set some of those bits to zero. Setting the back to one, however, requires wiping an entire block.
Needless to say, this strange usage pattern requires some trickery to make it transparent to the boring old block and character device abstraction in the kernel. The MTD interface accomplishes exactly that. (The more adventurous of you might want to take a look at the kernel source for the msm_nand platform driver, which is what powers Android's flash support.) This interface is exposed through /dev/mtd, and can be accessed and read as though they were regular files.
So then, when I look at this directory, here is what I see:
# ls /dev/mtdmtd4ro
mtd4
mtd3ro
mtd3
mtd2ro
mtd2
mtd1ro
mtd1
mtd0ro
mtd0
Not the most descriptive bit of output, but it's a start. A little more information can be gained by looking at /proc/mtd :
# cat /proc/mtddev: size erasesize namemtd0: 01fa0000 00020000 "boot"mtd1: 01fa0000 00020000 "cache" mtd2: 01fa0000 00020000 "recovery" mtd3: 15600000 00020000 "system" mtd4: 21c20000 00020000 "userdata"
Much better. This tells me the exact layout and size of the partitions on this device. The sizes are 32MB for the boot, cache, and recovery partitions, a comfy 358MB for the system partition, plus 566MB for the user data.
So then, how to back these up? That depends on how we want to restore things. Upon asking for help from the Cyanogenmod development IRC channel, I was advised to be careful to copy out-of-band data, or the flash metadata about each block, such as bad blocks and so on. I found that if I were to be using various low-level tools, this would have been a concern. However, I will be using fastboot to do the flashing, and so can rely on the bootloader to handle bad blocks and such.
So then, actually performing the backup is easy. The data will emerge from the NAND partition and be presented to by the kernel as a simple device:
cat /dev/mtd/mtd0 > /sdcard/boot-mtd0.img
Fun fact: my hunch from my last post about this phone not using a recovery partition was confirmed when I opened up my recovery backup to find nothing but ones. After copying each partition, and subsequently pulling the data off, I now have a working backup of every single relevant byte on my phone.
Or at least in theory I do. I still need to test this. There is only one way to test this, and that is the scary one: wipe a partition, see that something is wrong, and restore it. I chose boot as my victim:
fastboot erase boot
# Tense reboot. LG logo lights up. Fails to boot.
fastboot flash boot boot-mtd0.img
# *Really* tense reboot. LG logo lights up...and...
To my glee, the thing comes back to life! I've tempted fate and walked away unscathed! As of right now, I have a complete backup of the working state of my phone, and should anything go awry, I can fall back on these images, flashing them onto the device via fastboot.
So then, where do we go from here? In the background, I've downloaded and compiled my starting point: Cyanogenmod 7.1 for the Nexus One. For my next episode, I will naively attempt to plop the Nexus One image onto the phone and see what happens.
Stay tuned!