Когда я попробовал себя в написании хоть сколько нибудь сложного мода для Android - пришлось вплотную (а вернее с размаху носом) столкнуться с языком edify - на нём пишется updater-script в Android flashable пакетах. И столкновение это не прошло незамеченным для моей психики, вызвав ощущение собственной неполноценности, связанный с этим butthurt и лютобешеную ненависть к этому языку. Соответственно я начал искать иные пути, чтобы использовать милый сердцу за свою мощь, красоту и простоту язык Unix Shell скриптов. И теперь хочу поделиться с Вами опытом.
Целью моих изысканий было найти возможность отображения состояния хода установки обновления на экране телефона, ведь без этого можно было и так использовать скрипт Shell, вызыывая его из edify скрипта. Собственно это и было успешно достигнуто. Плюс несколько уменьшен размер Zip-обновления, оно занимает 91кБ, против 231 кБ у edify-версии.
Немного теории о том, как происходит установка Zip-архива из Recovery. Recovery извлекает из архива с обновлением файл META-INF/com/google/android/update-binary в /tmp, делает ему chmod 777 и запускает передавая три параметра: 1. API level. Это число от 1 до 3 (в моём случае это было 2). Для нас полностью бесполезен. 2. Дескриптор Pipe для обратной связи с Recovery. С ним подробнее разберёмся позднее. 3. Полное имя Zip-обновления. Тут я полагаю всё ясно.
Немного поковырявшись в исходниках update-binary от edify и изучив состояние системы при установке и происходящие в ней процессы, был рождён следующий код
Давайте разберёмся в нём. #!/sbin/sh Строка, указывающся ядру, что делать со скриптом (вернее чем его исполнять). Указывает на интерпретатор команд. interface="/proc/$$/fd/$2" Определение переменной хранящей адрес канала по которому мы будем общаться с Recovery. $$ превращается в PID текущего процесса, а $2 - передвавемый нам из Recovery номер дескрпптора канала. Всё, что мы будем писать в него Recovery будет воспринимать как команды. zip="$3" Получаем в переменную имя зипа, оно нам ещё пригодится. boot="mmcblk0p20" Переменная будет хранить имя файла устройства, хранящего boot.img. set_progress() ( echo set_progress 0.$1 > $interface ) ui_print() ( echo ui_print $1 > $interface ) Две строки, определяющие функции по работе с интерфейсом Recovery, аналогичные одноимённым командам edify. Как видим, используются две команды для этого интерфейса, ui_print (выводит текст в окошко на экране) и set_progress (передвигает прогресс-бар). cd /tmp/ set_progress 02 Мы готовимся к работе, переходя в каталог /tmp/ и передвигаем прогресс-бар на уровень 2 процента. Далее я не буду описывать команду set_progress, её смысл одинаков везде. if grep -q shooteru /default.prop ; then ui_print "Shooteru device!" ; else ui_print "This is not shooteru device!" ; exit 1 ; fi Проверяем, запущен ли скрипт на правильном устройстве (ведь работа скрипта для одного устройства на другом может закончиться необратимым повреждением этого устройства) и прерываем процесс если это не так. Аналог getprop из edify, но неполный. Заставить настоящий gerprop работать у меня не вышло. Обратите внимание на то, что мы пользуемся функцией ui_print которую определили выше. Далее я не буду описывать ui_print, из за его очевидности. Также обратите внимание на команду exit 1 - она предназначена для облегчения отладки скрипта, и одновременно прерывания его работы в случае если что то пошло не так как надо. В случае ошибки при работе скрипта он будет прерван, а Recovery выведет код ошибки, по которому будет можно легко найти место где эта ошибка произошла. grep -q /system /proc/mounts || mount /system || exit 2 Проверяем, смонтирован ли раздел /system, монтируем его если это не так, и прерываем работу с кодом 2 если монтирование не удалось. Далее я не буду описывать команду exit #, её смысл ясен и так. release=`grep 'ro.build.version.release' /system/build.prop|cut -d '=' -f 2` Получаем в переменную версию Android установленную на устройстве. Аналог getprop_file из edify. case $release in 4.1.1) ui_print "Android $release found, version is correct, continue";; 4.0.3) ui_print "Android $release found, version is correct, continue";; *) ui_print "Android $release found, version is incorrect, break"; exit 4 esac И тут же проверяем её. Это просто образец, на самом деле этот мод будет работать на любом устройстве и прошивке, где есть кастомное Recovery и установлен Busybox. unzip -o $zip tmp/* -d / >/dev/null || exit 5 Извлекаем из Zip-архива с обновлением каталог tmp/ со всеми файлами в каталог / (корень ФС, параметр -d) с перезаписью файлов при необходимости (параметр -o) chmod 0755 /tmp/mkbootimg || exit 6 chmod 0755 /tmp/unpackbootimg || exit 7 Придаём извлеченным файлам атрибут исполняемости, чтобы их можно было запустить. /tmp/unpackbootimg /dev/block/$boot "/tmp/" || exit 8 Распаковываем boot.img прямо из памяти устройства в каталог /tmp/ rm -r ramdisk Удаляем (на случай если какой-то скрипт ранее уже создал его) каталог ramdisk со всем его содержимым mkdir ramdisk || exit 9 Создаём этот каталог cd ramdisk || exit 10 И переходим в него. Обратите внимание, что после rm -r нет проверки на ошибку. Это сделано специально, ошибка здесь допустима, и более того - в нормальном режиме rm -r обязан выдать ошибку. zcat /tmp/$boot-ramdisk.gz | cpio -i || exit 11 Распаковываем GZip-упакованный CPIO-образ Ramidsk (также известен как initrd) в текущий каталог (ramdisk). echo sys.usb.config=adb >> /tmp/ramdisk/default.prop Записываем в конец файла /tmp/ramdisk/default.prop строку sys.usb.config=adb cp `which adbd` /tmp/ramdisk/sbin/adbd || exit 13 Находим полный путь к файлу adbd командой which и копируем его в /tmp/ramdisk/sbin/adbd cp /system/*bin/sh /tmp/ramdisk/sbin || exit 14 Копируем файл sh из каталога /system/bin/, /system/xbin/ или /system/xbin/ (уж где то shell то в системе обязан быть!) в /tmp/ramdisk/sbin/ chmod 0755 "/tmp/ramdisk/sbin/adbd" || exit 15 chmod 0755 "/tmp/ramdisk/sbin/sh" || exit 16 Придаём файлам права на исполняемость find . | cpio -o -H newc | gzip > /tmp/new-ramdisk.gz || exit 17 Упаквываем образ нового ramdisk cd - И возвращаемся в предыдущий текущий каталог /tmp/mkbootimg --kernel /tmp/$boot-zImage --ramdisk /tmp/new-ramdisk.gz --cmdline "`cat /tmp/$boot-cmdline`" --base `cat /tmp/$boot-base` --output /tmp/newboot.img || exit 18 Создаём новый boot.img dd if=/dev/zero of=/dev/block/$boot bs=65536 Стираем старый boot.img, заполняя раздел для него нулями dd if=/tmp/newboot.img of=/dev/block/$boot bs=65536 || exit 19 И записываем туда новый boot.img (на самом деле это всё вовсе не обязательно делать, можно было просто прописать --output /dev/block/$boot в команде создающей boot.img) rm /tmp/newboot.img /tmp/new-ramdisk.gz /tmp/$boot* /tmp/ramdisk/ /tmp/mkbootimg /tmp/unpackbootimg || exit 20 Удаляем всё после себя (не знаю как вас, а меня учили прибирать за собой) umount /system || exit 23 Размонтируем /system/
Всё. А мод этот добавляет поддержку ADB на значительно более ранней стадии загрузки системы, примерно спустя 8 секунд после включения, что даст возможность отлаживать процесс загрузки с гораздо более раннего момента, и даже вмешиваться в него. Статья оригинальная, автор идеи, разработок и технической реализации - я. Статья будет выложена также на форуме 4pda (под другим ником), не считайте это плагиатом. Скрина нет, так как скринить по сути нечего. Прикрепленный файл #1: [hide]5056_early_adbd_mod.zip[/hide] (90, 9 Kb)