Не так давно мой Galaxy S GT-I9000 начал спонтанно перезагружаться с сообщением Internal SD card removed unexpectedly, а потом и вовсе зависать в boot-е.
Не найдя работающего решения в интернете (а проблема довольно распространенная и решений предлагается много), и ничего не понимая в утсройстве андройда, я решил, что раз уж я программист, надо все-таки попытаться разобраться самому.
Если у вашего телефона похожая проблема, или вам интересен процесс исследования таких проблем, прошу под кат.
Прежде всего: я не специалист в Android или Linux, и может быть, кому-то этот пост покажется тривиальным. Но так как нормального решения проблемы я в интернете не нашел, надеюсь, что пост окажется полезным.
И так в чем же проблема?
Немного погуглив, мы узнаем, что «Internal SD card» соответствует девайс файлу /dev/block/mmcblk0 на котором должны быть два партишена: mmcblk0p1(vfat, для /data) и mmcblk0p2 (ext2, для /sdcard).
Зайдем в recovery (Home+VolumeUp+Power) и через adb(нужен Android SDK и USB driver, если вы на Windows; подробго тут http://developer.android.com/guide/developing/device.html) проверим наличие mmcblk0:
$ adb shell
/ # ls -l /dev/block/
В моем случае mmcblk0 отсутствовал.
Ищем разнообразные логи:
/ # find -name *log*
./mnt/.lfs/logo_latona.jpg
./mnt/.lfs/logo.jpg
./mnt/.lfs/logo_s1ntt.jpg
find: ./cache/RECOVERY: No such file or directory
./cache/recovery/recovery_kernel_log
./cache/recovery/log
./cache/recovery/last_log
...
Логов конечно много, но так как я подозревал HW проблему. первым делом заинтересовался kernel логами.
/ # grep mmc /cache/recovery/recovery_kernel_log
...
<6>[ 0.717702] mmc0: SDHCI controller on samsung-hsmmc [s3c-sdhci.0] using ADMA
...
<3>[ 2.060251] mmc0: error -110 whilst initialising MMC card
...
Ага! Что же за error 110? Гугл подсказывает: ETIMEDOUT. Судя по всему вот сорс код, печающий эту ошибку: http://lxr.free-electrons.com/source/drivers/mmc/core/mmc.c#L1326
На этом этапе можно конечно попытаться сдать аппарат по гарантии, но мне было лень(да и не уверен, что телефон поменяли бы), и появилась вот какая идея: что если заменить проблемную внутреннюю СД-карточку на внешнюю?
На эту мысль меня натолкнул то факт. что когда я подключал внешнюю карточку, она появлялась как раз как mmcblk0.
Вот хороший топик, о том как создать нужные partitions:
http://forum.cyanogenmod.com/topic/6433-solved-messed-up-partitions-on-internal-storage
И еще один: http://forum.xda-developers.com/showthread.php?t=534714
А вот так все должно выглядеть в результате:
/ # ls /dev/block/mmc*
/dev/block/mmcblk0
/dev/block/mmcblk0p1
/dev/block/mmcblk0p2
Итак осталось только использовать наш новый mmcblk0.
Нужно понять, кто и когда маунтит mmcblk0p1 и mmcblk0p2 в /sdcard и /data.
Поищем fstab:
/ # find -name *fstab*
./system/etc/vold.fstab
./voodoo/root/etc/fstab
./voodoo/run/cwm_recovery.fstab
./voodoo/run/cwm.fstab
./res/recovery.fstab
/ #
Из всего найденного vold.fstab больше всего похож на то, что нам нужно (voodoo это система скриптов для конвертирования самсунговской rfs в ext4, а cwm это clockwork mod).
Из гугла не сложно узнать, что vold это демон ответсвенный за маунт СД-карточек. Посмотрим его конфиг:
## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##
#######################
## Regular device mount
##
## Format: dev_mount <mount_point> <sysfs_path1...>
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################
# sdcard mount for the P1
# internal sdcard
{
ums_path = /sys/devices/platform/usb_mass_storage/lun0/file
discard = disable
asec = disable
}
dev_mount sdcard /mnt/sdcard 1 /devices/platform/s3c-sdhci.0/mmc_host/mmc0
# externel sdcard
{
ums_path = /sys/devices/platform/usb_mass_storage/lun1/file
asec = enable
}
dev_mount sdcard1 /mnt/sdcard/external_sd auto /devices/platform/s3c-sdhci.2/mmc_host/mmc2
#end line ## keep this line
Нетрудно догадаться, что vold маунтит первый партишен mmcblk0 как /mnt/sdcard (а /sdcard это soft link на /mnt/sdcard).
Попытаемся поменять местами mmc0 и mmc2:
## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##
#######################
## Regular device mount
##
## Format: dev_mount <mount_point> <sysfs_path1...>
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################
# externel sdcard for /mnt/sdcard
{
ums_path = /sys/devices/platform/usb_mass_storage/lun1/file
discard = disable
asec = disable
}
dev_mount sdcard /mnt/sdcard 1 /devices/platform/s3c-sdhci.2/mmc_host/mmc2
# internal sdcard for /mnt/sdcard/external_sd
{
ums_path = /sys/devices/platform/usb_mass_storage/lun0/file
asec = enable
}
dev_mount sdcard1 /mnt/sdcard/external_sd auto /devices/platform/s3c-sdhci.0/mmc_host/mmc0
#end line ## keep this line
Важно оставить в конфиге ссылку на external_sd - иначе будем иметь вот такой неприятный крэш при попытке установить аппликации:
D/Vold ( 196): VolumeManager::isMountedAsec -> Can not find the label(/mnt/sdcard/external_sd)
E/JavaBinder( 902): *** Uncaught remote exception! (Exceptions are not yet supported across processes.)
...
E/AndroidRuntime( 902): *** FATAL EXCEPTION IN SYSTEM PROCESS: PackageManager
...
который приводит к перезагрузке системы.
Кто же маунтит mmcblk0p2?
Посмотрим на init.rc:
/ # grep mmcblk init.rc
mount rfs /dev/block/mmcblk0p2 /data nosuid nodev check=no
# mount rfs /dev/block/mmcblk0p2 /data nosuid nodev crypt check=no
/ #
тут нам ничего менять не надо.
Вроде бы все. Перезагружаем и та-дам!! все работает:)
Интересные ссылки по теме:
- Отличное описание android boot process
http://www.androidenea.com/2009/06/android-boot-process-from-power-on.html
- Android init language
- Sysfs overview