В первой части мы научились перепаковывать официальную прошивку из формата RUU в формат пакета обновлений, что дало нам возможность использовать созданную нами прошивку, не опасаясь затирания модифицированного раздела восстановления (recovery rom). И тем временем, пока HTC воюет с хорошими ресурсами, мы продолжим изучать и улучшать прошивку.
В предыдущей части, хоть мы и создали прошивку, которая загружается и работает как часы, мы бы хотели расширить базовый функционал оной. Одним из самых востребованных расширений является поддержка работы с правами суперпользователя (root). Также сюда можно отнести интегрирование busybox. Кроме того, мы научимся запускать произвольные скрипты при старте системы и адаптируем ramdisk под свои нужды.
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 будем ориентироваться на те ссылки, которые были созданы в изначальной прошивке.
Единственным линком, указывающим не на toolbox является dumpcrash:
Это также стоит учесть при формировании скрипта обновления.
Предположим, что мы решили, что главным у нас будет busybox. У меня получилось, что следующие апплеты toolbox уникальны:
Не забудем удалить ссылки из самой прошивки.
Теперь мы можем смело помещать наши ссылки по указанному пути, для чего откорректируем скрипт обновления:
Однако, просто поместить ссылки в отдельную папку — мало. Нужно расширить путь поиска исполняемых файлов для системы. Для этого нам понадобиться дополнить переменную $PATH, которая в случае с андроидом на HTC Hero определяется в /init.rc
Все файлы корневой директории являются частью ramdisk-а (как и некоторые другие вложенные директории). Воспользуемся знаниями из первой части: распакуем boot, после чего мы можем изменить переменную PATH
Прежде чем мы соберем ramdisk обратно, сделаем еще несколько полезных дел.
Для упрощения жизни нам бы хотелось иметь следующее:
Для этого обратим свой взор на /default.prop, в котором среди прочего хранятся следующие настройки:
Для осуществления третьего пункта, нам понадобиться модифицировать скрипт инициализации /init.rc. Данный скрипт как водится, представляет собойсобственный велосипед андроид скрипт на Android Init Language. Ознакомиться с форматом предлагаю в исходниках android. Нам же интересна возможность добавить собственный сервис (мы не можем добавить свои команды прямо в триггер, потому как там набор команд строго ограничен):
Осталось запустить наш сервис (опция disabled, говорит, что данный сервис не будет стартовать автоматически). Для этого последнюю команду из тригера on boot переместим в наш собственный триггер окончания выполнения скриптов и вызовем наш сервис.
Также создадим два простых скрипта в /system/etc/init.d для демонстрации того, что все это работает. Первый будет делать стандартное echo (Hello World!, как же без него), а второй очищать кеш, и сообщать init скрипту, что мы уже закончили и можно дальше продолжать загружаться.
И последний штрих — установим им права на запуск (все там же — в скрипте обновления прошивки)
Для многих, наверное, самый актуальный вопрос. Для тех терпеливых, кто дочитал.
Не смотря на то, что в исходниках есть своя реализация su, она нам не подходит, потому как основной ее целью является запуск приложений суперпользователем (или из adb shell) с правами других user-ов.
Мы же воспользуемся разработкой ChainsDD — приложением Superuser 2.1. Суть приложения аналогична знакомым нам sudo, или даже Admin Approval Mode из системы Windows. Если приложение хочет повысить свои права до прав суперпользователя (и не только), у пользователя запрашивается разрешение. Также можно запомнить принятое правило и автоматически применять для всех будущих вызовов.
Воспользуемся уже собранным приложением для Android 2.1, хотя всегда есть возможность изучить и собрать самому из исходников.
Приложение состоит из двух компонент:

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

В предыдущих и будущих сериях
В предыдущей части, хоть мы и создали прошивку, которая загружается и работает как часы, мы бы хотели расширить базовый функционал оной. Одним из самых востребованных расширений является поддержка работы с правами суперпользователя (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, достаточно запустить его на устройстве без параметров:
- $ adb remount && adb push busybox /cache/
- $ adb shell chmod 0755 /cache/busybox
- $ adb shell /cache/busybox | tail
- tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top,
- touch, tr, traceroute, true, tty, ttysize, tunctl, udpsvd, umount,
- uname, uncompress, unexpand, uniq, unix2dos, unlzma, unlzop, unzip,
- uptime, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, watch,
- watchdog, wc, wget, which, who, whoami, xargs, yes, zcat, zcip
Для получения списка доступных апплетов для toolbox будем ориентироваться на те ссылки, которые были созданы в изначальной прошивке.
- $ find habrrom/system/bin/ -type l -printf '%f, ' | tail
- getprop, insmod, ifconfig, setprop, wipe, watchprops, log, sync, schedtop, ioctl, rm,
- sleep, notify, sendevent, dmesg, df, route, vmstat, mv, iftop, rmmod,
- dd, renice, kill, mount, start, rmdir, ps, ln, cmp, dumpcrash, top, getevent,
- umount, mkdir, setconsole, printenv, newfs_msdos, chown, cat, hd, chmod, date,
- stop, smd, netstat, ls, lsmod, id,
Единственным линком, указывающим не на toolbox является dumpcrash:
- $ ls -o habrrom/system/bin/ | grep dumpstate
- lrwxrwxrwx 1 astar 9 2010-06-16 03:59 dumpcrash -> dumpstate
- -rwxr-xr-x 1 astar 14296 2010-06-16 03:55 dumpstate
Это также стоит учесть при формировании скрипта обновления.
Предположим, что мы решили, что главным у нас будет busybox. У меня получилось, что следующие апплеты toolbox уникальны:
- getevent, getprop, iftop, ioctl, log, newfs_msdos, notify, schedtop,
- sendevent, setprop, smd, start, stop, top, umount, vmstat, watchprops, wipe
И предположим, что мы хотим создавать ссылки на этапе установки прошивки, для этого в скрипт обновления нам нужно будет добавить строчки следующего вида:
- symlink dumpstate SYSTEM:bin/dumpcrash
- #
- symlink toolbox SYSTEM:bin/getprop
- # повторяем процедуру для необходимых апплетов toolbox
- symlink busybox SYSTEM:xbin/[
- # повторяем процедуру для всех апплетов busybox
Не забудем удалить ссылки из самой прошивки.
- $ rm `find habrrom/system/bin/ -type l`
Плюс, нам понадобиться, выставить правильные права на busybox
- set_perm 0 0 04755 SYSTEM:xbin/busybox
Попробуем усложнить себе задачу. Давайте поместим ссылки для busybox в отдельную директорию, например /system/xbin/bb. Для этого нам понадобится в структуре прошивки добавить непустую папку (пустую папку, откажется копировать скрипт обновления):
- $ mkdir habrrom/system/xbin/bb
- $ touch habrrom/system/xbin/bb/placeholder
Теперь мы можем смело помещать наши ссылки по указанному пути, для чего откорректируем скрипт обновления:
- symlink ../busybox SYSTEM:xbin/bb/[
- # и так далее
Модификация ramdisk
Однако, просто поместить ссылки в отдельную папку — мало. Нужно расширить путь поиска исполняемых файлов для системы. Для этого нам понадобиться дополнить переменную $PATH, которая в случае с андроидом на HTC Hero определяется в /init.rc
- $ adb shell cat /init.rc | grep "export PATH"
- export PATH /sbin:/system/sbin:/system/bin:/system/xbin
Все файлы корневой директории являются частью ramdisk-а (как и некоторые другие вложенные директории). Воспользуемся знаниями из первой части: распакуем boot, после чего мы можем изменить переменную PATH
- $ cat habrrom.boot/ramdisk/init.rc | grep "export PATH"
- export PATH /sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb
Прежде чем мы соберем ramdisk обратно, сделаем еще несколько полезных дел.
Для упрощения жизни нам бы хотелось иметь следующее:
- Возможность монтирования файловой системы с правами на запись
- Отладка по usb, включенная по-умолчанию. Иначе, если что-то пойдет не так, мы не сможем получить хоть какую-то полезную информацию о причинах, так как сервис adbd будет отключен и как следствие — adb logcat во время загрузки будет недоступен
- Запуск произвольных скриптов при загрузке системы (самыми популярными вариантами использования являются: включение app2sd, перенос dalvik-cache в /cache)
Для этого обратим свой взор на /default.prop, в котором среди прочего хранятся следующие настройки:
- ro.secure — используется то тут то там по всей системе, но из интересующих нас свойств, включает adb remount на запись а, также, adb shell выполняется с правами суперпользователя. Выставим значение в 0
- persist.service.adb.enable — отвечает за старт сервиса adbd, который нам помогает совершать удаленное взаимодействие с телефоном по средством adb. Выставляем в 1
Скрипты инициализации
Для осуществления третьего пункта, нам понадобиться модифицировать скрипт инициализации /init.rc. Данный скрипт как водится, представляет собой
- service sysinit /system/bin/logwrapper /system/xbin/busybox run-parts /system/etc/init.d
- disabled
- oneshot
Т.е. мы назвали наш сервис sysinit, который при своем старте выполнит run-parts /system/etc/init.d, что в свою очередь запустит все скрипты из соответствующей папки в порядке отсортированном по алфавиту. logwrapper нам необходим, дабы перенаправить вывод вместо /dev/null (по-умолчанию) в систему логирования (доступную по logcat).Осталось запустить наш сервис (опция disabled, говорит, что данный сервис не будет стартовать автоматически). Для этого последнюю команду из тригера on boot переместим в наш собственный триггер окончания выполнения скриптов и вызовем наш сервис.
- # не сейчас
- # class_start default
- start sysinit
-
- on property:habr.sysinit.done=1
- # вот сейчас
- class_start default
Также создадим два простых скрипта в /system/etc/init.d для демонстрации того, что все это работает. Первый будет делать стандартное echo (Hello World!, как же без него), а второй очищать кеш, и сообщать init скрипту, что мы уже закончили и можно дальше продолжать загружаться.
- $ cat habrrom/system/etc/init.d/00banner
- #!/system/bin/sh
- echo "Hello habrahabr!";
- $ cat habrrom/system/etc/init.d/99complete
- #!/system/bin/sh
- sync;
- setprop habr.sysinit.done 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, хотя всегда есть возможность изучить и собрать самому из исходников.
Приложение состоит из двух компонент:
- native модуль su. Который при запросе на изменение прав перенаправляет запрос в собственный Activity и ждет реакции пользователя
- приложение Superuser.apk — набор интерфейсов (Activity), отвечающих за взаимодействие с пользователем, хранение настроек.


Для того, чтобы добавить в нашу прошивку указанный функционал — добавим модули в соответствующие разделы системы,
- $ cp su habrrom/system/xbin/
- $ cp Superuser.apk habrrom/system/app/
и настроим права для исполняемого файла (плюс линк в /system/bin/, так как некоторые приложения могут вызывать su по абсолютному пути)
- symlink ../xbin/su SYSTEM:bin/su
- set_perm 0 0 06755 SYSTEM:xbin/su
На этом все.
Прикладываю небольшой архив, в качестве итогового резюме тому, что было сделано в этой статье. Скрипты, busybox, Superuser и прочее. Для любопытных.
В этот раз получилось как-то уж очень по-линуксовому, и занудненько. Но в следующий раз рассмотрим тему повеселее — перепаковка системных приложений. А пока, финальная точка:

В предыдущих и будущих сериях