lunes, 26 de diciembre de 2011

Booting an unbootable Nexus S

Yes, I made it. A week later of getting a Nexus S device as a replacement for my broken DHD, I managed to brick it. "How come? These are unbrickable devices". Not true.

Most of todays phone devices have a NAND portion of the memory for holding the internal partitions of the device. As you may know, NAND memories can be written a finite (but supposedly large) number of times. Well, this second hand device holded exactly 5 boot flashes in one week. Ok, on average it may look high, but ... only five man. In absolute terms.

Internal memory layout
In my Nexus S this is the internal memory distribution. We access them through Memory Technology Layout linux subsystem:


/sdcard # cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00200000 00040000 "bootloader"
mtd1: 00140000 00040000 "misc"
mtd2: 00800000 00040000 "boot"
mtd3: 00800000 00040000 "recovery"
mtd4: 1d580000 00040000 "cache"
mtd5: 00d80000 00040000 "radio"
mtd6: 006c0000 00040000 "efs"

As you can see, there are several partitions, all of them accesible through /dev/mtd/mtd[0-6] special device.
And luckily for us boot and recovery has the same size. Some of them:
  • bootloader : well, it has the bootloader. It's basically a small program with the ability to boot other partitions, as well as listening to "fastboot" commands over usb.
  • boot : on a second stage, a kernel image plus a initrd (ram disk image) will be loaded from this partition. If this partition is corrpted, it will autoboot to recovery partition
  • recovery : it is an alternate boot partition. It holds a kernel also, and an specialized initrd to perform some other recovery functions. You have here a mini-os and very important, an adb server that you can use to send adb commands over the usb.
Bootloader listens to fastboot commands: fastboot is a very interesting feature per se, on (almost) every android phone. There's a common protocol and a fastboot command on Android SDk, to tell the device to flash any partition with raw data, an even booting from an external image. If you can access to bootloader, you can recover from almost everything via fastboot commands.

What the hell happened
All you need to mess the things up is ... well, just flash something into MTD. With a sufficient number of flashes, anybody will eventually brick their devices. This is amazing, because at least since ICS (Android 4) every device will flash a default boot record into recovery partition. Every single time it boots

I was flashing a new custom kernel through recovery when I noticed a failure. Properly looking at the recovery.log file, I could notice a failure on several blocks of the partition.


flashing boot from /sdcard/clockworkmod/backup/2011-12-24.18.28.01-CM9-18+g2//boot.img
mtd: successfully wrote block at 0
mtd: successfully wrote block at 40000
mtd: successfully wrote block at 80000
mtd: successfully wrote block at c0000
mtd: successfully wrote block at 100000
mtd: successfully wrote block at 140000
mtd: successfully wrote block at 180000
mtd: successfully wrote block at 1c0000
mtd: successfully wrote block at 200000
mtd: successfully wrote block at 240000
mtd: successfully wrote block at 280000
mtd: successfully wrote block at 2c0000
mtd: not writing bad block at 0x00300000 (ret 1 errno 2)
mtd: not writing bad block at 0x00340000 (ret 1 errno 2)
mtd: successfully wrote block at 380000
mtd: successfully wrote block at 3c0000
mtd: successfully wrote block at 400000
mtd: successfully wrote block at 440000
mtd: successfully wrote block at 480000
mtd: successfully wrote block at 4c0000
mtd: successfully wrote block at 500000
mtd: successfully wrote block at 540000
mtd: successfully wrote block at 580000
mtd: successfully wrote block at 5c0000
mtd: successfully wrote block at 600000
mtd: successfully wrote block at 640000
mtd: successfully wrote block at 680000
mtd: successfully wrote block at 6c0000
mtd: successfully wrote block at 700000
mtd: successfully wrote block at 740000
mtd: successfully wrote block at 780000
mtd: successfully wrote block at 7c0000
error writing bootError while flashing boot image!mtd: successfully wrote block at 0

The problem can be reproduced any time, just by flashing any boot.img file (for instance from a recovery backup file):


flash_image boot boot.img

Partially solving it: boot through fastboot
Fastboot has a special mode for booting an image from the PC itself. It will push the image to a temporary memory segment, and boot to it. Without flashing. It can be done with this command on the PC:

fastboot boot boot.img

This solution is nice, but you will need a PC every time you need to reboot your phone. And I tend to do that ... well, a few times a day.

Definitive solution
The easiest solution I could find was: flashing boot.img over the recovery partition.
It should work as the boot procedure described above goes through both boot and recovery partition.


/sdcard # flash_image recovery boot.img.orig
flashing recovery from boot.img.orig
mtd: successfully wrote block at 0
mtd: successfully wrote block at 40000
mtd: successfully wrote block at 80000
mtd: successfully wrote block at c0000
mtd: successfully wrote block at 100000
mtd: successfully wrote block at 140000
mtd: successfully wrote block at 180000
mtd: successfully wrote block at 1c0000
mtd: successfully wrote block at 200000
mtd: successfully wrote block at 240000
mtd: successfully wrote block at 280000
mtd: successfully wrote block at 2c0000
mtd: successfully wrote block at 300000
mtd: successfully wrote block at 340000
mtd: successfully wrote block at 380000
mtd: successfully wrote block at 3c0000
mtd: successfully wrote block at 400000
mtd: successfully wrote block at 440000
mtd: successfully wrote block at 480000
mtd: successfully wrote block at 4c0000
mtd: successfully wrote block at 500000
mtd: successfully wrote block at 540000
mtd: successfully wrote block at 580000
mtd: successfully wrote block at 5c0000
mtd: successfully wrote block at 600000
mtd: successfully wrote block at 640000
mtd: successfully wrote block at 680000
mtd: successfully wrote block at 6c0000
mtd: successfully wrote block at 700000
mtd: successfully wrote block at 740000
mtd: successfully wrote block at 780000
mtd: successfully wrote block at 7c0000
mtd: successfully wrote block at 0
/sdcard # reboot

Alternative solutions... (not tested)
Some people shrink their kernels so they can fit on the working space. It left me 2.8Mb. I made in fact a boot.img with that size, but after the kernel and ramdisk there is some more data that I haven't figured it out yet what it does... or perhaps it's a padding problem or something. Don't know. It didn't worked.

Some other people actually remaps the memory layout, with a new definition of partitions... http://forum.xda-developers.com/showthread.php?t=704560

The most radical is to have a custom bootloader: http://forum.xda-developers.com/showthread.php?t=1233273


Caveats
Well, I don't have a recovery anymore. But I can boot into one from the PC. And that's much more unlikely to happen that having turn boot the phone itself. It would be done with:


fastboot boot clockwordmod-whatever-version.img


Conclusions
I'm not sure if this change in ICS is intended or not from google ... but flashing the recovery partition on every single reboot seems no good to me. Maybe they are trying to burn your NAND  making impossible to upgrade the OS? Don't think so but ... who knows. People happy with their devices for a long time is not a good commercial policy... Anyway, it is good practice to remove that (/system/etc/flash_recovery.sh on stock ICS) and have backups of all your partitions, in fastboot (raw) format. And always a PC with fastboot and ADB ready ;-)

No hay comentarios:

Publicar un comentario