Pull to refresh

Разработка и модификация прошивки для Android телефонов. Часть 2

Reading time9 min
Views64K
В первой части мы научились перепаковывать официальную прошивку из формата RUU в формат пакета обновлений, что дало нам возможность использовать созданную нами прошивку, не опасаясь затирания модифицированного раздела восстановления (recovery rom). И тем временем, пока HTC воюет с хорошими ресурсами, мы продолжим изучать и улучшать прошивку.
В предыдущей части, хоть мы и создали прошивку, которая загружается и работает как часы, мы бы хотели расширить базовый функционал оной. Одним из самых востребованных расширений является поддержка работы с правами суперпользователя (root). Также сюда можно отнести интегрирование busybox. Кроме того, мы научимся запускать произвольные скрипты при старте системы и адаптируем ramdisk под свои нужды.

Busybox



busybox — это набор консольных unix утилит, ориентированный на малый размер и производительность, что так актуально для мобильных систем. Вместе с системой android поставляется свой набор утилит — toolbox, который предоставляет минимально необходимых функционал для системы, и как следствие более простой в количественном и функциональном плане. Наличие busybox в системе, с одной стороны, позволит нам, как разработчикам, чувствовать себя более комфортно при удаленной работе на устройстве, с другой, позволит писать сложные скрипты, и, например, реализовать механизм запуска собственных скриптов при загрузке, используя run-parts. Также стоит учитывать, что для некоторых android приложений (особенно те, которые используют root) наличие busybox — обязательно.

Дабы упростить себе жизнь, воспользуемся уже собранным busybox под нашу платформу. Например, 1.16.0 от небезызвестного modaco можно забрать тут. Кто смел духом, и обладает лишним временем, может собрать busybox из оффициального дерева (немного напильника по адаптации к андроидовскому toolchain-у, и bionic — андроидовской реализации libc), либо воспользоваться инструкцией XVilka по сборке с crosstool-ng и uCLibc, либо собрать из ветки cyanogenmod, где уже решены проблемы с bionic.
Итак, прежде чем мы добавим busybox, в систему нам нужно решить несколько идеологических моментов:
  • При общей схеме использования busybox/toolbox мы должны положить исполняемый файл и создать ссылки на него с именами апплетов. Ссылки должны быть доступны по пути из переменной $PATH. Где хранить ссылки для busybox? В /system/bin? /system/xbin? отдельная директория?
  • Использовать заранее созданные ссылки, или генерировать на этапе установки прошивки?
    В примере из первой части мы использовали заранее созданные ссылки для toolbox. Но данный вариант затруднителен, если разработка прошивки ведется на системе Windows, где есть определенные проблемы с символическими ссылками.
  • В зависимости от сборки busybox мы можем перекрыть набор команд, который уже доступен в toolbox. Кто главнее?
    С одной стороны, busybox предоставляет более широкий функционал (как пример: буквенное задание прав для chmod), но с другой стороны — мы можем захотеть исключить уже реализованные утилиты из busybox для уменьшения размера набора.

Чтобы узнать, какие апплеты поддерживает busybox, достаточно запустить его на устройстве без параметров:
  1. $ adb remount && adb push busybox /cache/
  2. $ adb shell chmod 0755 /cache/busybox
  3. $ adb shell /cache/busybox | tail
  4.         tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top,
  5.         touch, tr, traceroute, true, tty, ttysize, tunctl, udpsvd, umount,
  6.         uname, uncompress, unexpand, uniq, unix2dos, unlzma, unlzop, unzip,
  7.         uptime, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, watch,
  8.         watchdog, wc, wget, which, who, whoami, xargs, yes, zcat, zcip

Для получения списка доступных апплетов для toolbox будем ориентироваться на те ссылки, которые были созданы в изначальной прошивке.
  1. $ find habrrom/system/bin/ -type l -printf '%f, ' | tail
  2. getprop, insmod, ifconfig, setprop, wipe, watchprops, log, sync, schedtop, ioctl, rm,
  3. sleep, notify, sendevent, dmesg, df, route, vmstat, mv, iftop, rmmod,
  4. dd, renice, kill, mount, start, rmdir, ps, ln, cmp, dumpcrash, top, getevent,
  5. umount, mkdir, setconsole, printenv, newfs_msdos, chown, cat, hd, chmod, date,
  6. stop, smd, netstat, ls, lsmod, id,

Единственным линком, указывающим не на toolbox является dumpcrash:
  1. $ ls -o  habrrom/system/bin/ | grep dumpstate
  2. lrwxrwxrwx 1 astar       9 2010-06-16 03:59 dumpcrash -> dumpstate
  3. -rwxr-xr-x 1 astar   14296 2010-06-16 03:55 dumpstate

Это также стоит учесть при формировании скрипта обновления.
Предположим, что мы решили, что главным у нас будет busybox. У меня получилось, что следующие апплеты toolbox уникальны:
  1. getevent, getprop, iftop, ioctl, log, newfs_msdos, notify, schedtop,
  2. sendevent, setprop, smd, start, stop, top, umount, vmstat, watchprops, wipe
И предположим, что мы хотим создавать ссылки на этапе установки прошивки, для этого в скрипт обновления нам нужно будет добавить строчки следующего вида:
  1. symlink dumpstate SYSTEM:bin/dumpcrash
  2. #
  3. symlink toolbox SYSTEM:bin/getprop
  4. # повторяем процедуру для необходимых апплетов toolbox
  5. symlink busybox SYSTEM:xbin/[
  6. # повторяем процедуру для всех апплетов busybox

Не забудем удалить ссылки из самой прошивки.
  1. $ rm `find habrrom/system/bin/ -type l`
Плюс, нам понадобиться, выставить правильные права на busybox
  1. set_perm 0 0 04755 SYSTEM:xbin/busybox
Попробуем усложнить себе задачу. Давайте поместим ссылки для busybox в отдельную директорию, например /system/xbin/bb. Для этого нам понадобится в структуре прошивки добавить непустую папку (пустую папку, откажется копировать скрипт обновления):
  1. $ mkdir habrrom/system/xbin/bb
  2. $ touch habrrom/system/xbin/bb/placeholder

Теперь мы можем смело помещать наши ссылки по указанному пути, для чего откорректируем скрипт обновления:
  1. symlink ../busybox SYSTEM:xbin/bb/[
  2. # и так далее


Модификация ramdisk



Однако, просто поместить ссылки в отдельную папку — мало. Нужно расширить путь поиска исполняемых файлов для системы. Для этого нам понадобиться дополнить переменную $PATH, которая в случае с андроидом на HTC Hero определяется в /init.rc
  1. $ adb shell cat /init.rc | grep "export PATH"
  2.     export PATH /sbin:/system/sbin:/system/bin:/system/xbin

Все файлы корневой директории являются частью ramdisk-а (как и некоторые другие вложенные директории). Воспользуемся знаниями из первой части: распакуем boot, после чего мы можем изменить переменную PATH
  1. $ cat habrrom.boot/ramdisk/init.rc | grep "export PATH"
  2.     export PATH /sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb

Прежде чем мы соберем ramdisk обратно, сделаем еще несколько полезных дел.
Для упрощения жизни нам бы хотелось иметь следующее:
  1. Возможность монтирования файловой системы с правами на запись
  2. Отладка по usb, включенная по-умолчанию. Иначе, если что-то пойдет не так, мы не сможем получить хоть какую-то полезную информацию о причинах, так как сервис adbd будет отключен и как следствие — adb logcat во время загрузки будет недоступен
  3. Запуск произвольных скриптов при загрузке системы (самыми популярными вариантами использования являются: включение app2sd, перенос dalvik-cache в /cache)

Для этого обратим свой взор на /default.prop, в котором среди прочего хранятся следующие настройки:
  • ro.secure — используется то тут то там по всей системе, но из интересующих нас свойств, включает adb remount на запись а, также, adb shell выполняется с правами суперпользователя. Выставим значение в 0
  • persist.service.adb.enable — отвечает за старт сервиса adbd, который нам помогает совершать удаленное взаимодействие с телефоном по средством adb. Выставляем в 1


Скрипты инициализации



Для осуществления третьего пункта, нам понадобиться модифицировать скрипт инициализации /init.rc. Данный скрипт как водится, представляет собой собственный велосипед андроид скрипт на Android Init Language. Ознакомиться с форматом предлагаю в исходниках android. Нам же интересна возможность добавить собственный сервис (мы не можем добавить свои команды прямо в триггер, потому как там набор команд строго ограничен):
  1. service sysinit /system/bin/logwrapper /system/xbin/busybox run-parts /system/etc/init.d
  2.     disabled
  3.     oneshot
Т.е. мы назвали наш сервис sysinit, который при своем старте выполнит run-parts /system/etc/init.d, что в свою очередь запустит все скрипты из соответствующей папки в порядке отсортированном по алфавиту. logwrapper нам необходим, дабы перенаправить вывод вместо /dev/null (по-умолчанию) в систему логирования (доступную по logcat).
Осталось запустить наш сервис (опция disabled, говорит, что данный сервис не будет стартовать автоматически). Для этого последнюю команду из тригера on boot переместим в наш собственный триггер окончания выполнения скриптов и вызовем наш сервис.
  1.     # не сейчас
  2.     # class_start default
  3.     start sysinit
  4.  
  5. on property:habr.sysinit.done=1
  6.     # вот сейчас
  7.     class_start default

Также создадим два простых скрипта в /system/etc/init.d для демонстрации того, что все это работает. Первый будет делать стандартное echo (Hello World!, как же без него), а второй очищать кеш, и сообщать init скрипту, что мы уже закончили и можно дальше продолжать загружаться.
  1. $ cat habrrom/system/etc/init.d/00banner
  2. #!/system/bin/sh
  3. echo "Hello habrahabr!";
  4. $ cat habrrom/system/etc/init.d/99complete
  5. #!/system/bin/sh
  6. sync;
  7. setprop habr.sysinit.done 1

И последний штрих — установим им права на запуск (все там же — в скрипте обновления прошивки)
  1. set_perm_recursive 0 2000 0755 0755 SYSTEM:etc/init.d

Права суперпользователя. Root.



Для многих, наверное, самый актуальный вопрос. Для тех терпеливых, кто дочитал.
Не смотря на то, что в исходниках есть своя реализация su, она нам не подходит, потому как основной ее целью является запуск приложений суперпользователем (или из adb shell) с правами других user-ов.
Мы же воспользуемся разработкой ChainsDD — приложением Superuser 2.1. Суть приложения аналогична знакомым нам sudo, или даже Admin Approval Mode из системы Windows. Если приложение хочет повысить свои права до прав суперпользователя (и не только), у пользователя запрашивается разрешение. Также можно запомнить принятое правило и автоматически применять для всех будущих вызовов.
Воспользуемся уже собранным приложением для Android 2.1, хотя всегда есть возможность изучить и собрать самому из исходников.
Приложение состоит из двух компонент:
  1. native модуль su. Который при запросе на изменение прав перенаправляет запрос в собственный Activity и ждет реакции пользователя
  2. приложение Superuser.apk — набор интерфейсов (Activity), отвечающих за взаимодействие с пользователем, хранение настроек.



Для того, чтобы добавить в нашу прошивку указанный функционал — добавим модули в соответствующие разделы системы,
  1. $ cp su habrrom/system/xbin/
  2. $ cp Superuser.apk habrrom/system/app/

и настроим права для исполняемого файла (плюс линк в /system/bin/, так как некоторые приложения могут вызывать su по абсолютному пути)
  1. symlink ../xbin/su SYSTEM:bin/su
  2. set_perm 0 0 06755 SYSTEM:xbin/su

На этом все.
Прикладываю небольшой архив, в качестве итогового резюме тому, что было сделано в этой статье. Скрипты, busybox, Superuser и прочее. Для любопытных.
В этот раз получилось как-то уж очень по-линуксовому, и занудненько. Но в следующий раз рассмотрим тему повеселее — перепаковка системных приложений. А пока, финальная точка:



В предыдущих и будущих сериях
  1. Часть 1. Создание прошивки в формате update.zip на основе RUU. Распаковка/запаковка boot. Скрипт обновления. Подпись пакета обновления и приложений.
  2. Часть 2. Добавление busybox. Добавление root. Монтирование на запись. Скрипт инициализации. Редактирование ramdisk.
Tags:
Hubs:
+48
Comments10

Articles

Change theme settings