Привет всем!
Сегодня я попробую ответить на вопрос, который многих волнует многих: «Как сделать дерево для сборки Андроид».
Часть 1
Что такое деревья, зачем нужны, с чем едят.Дерево-это патч, который накладывают на исходники Андроид для добавления поддержки какого-то устройства. То есть исходники Андроид, которые вы скачали, содержат набор «сделай Андроид сам» + деревья для Нексусов. Для других устройств нужны деревья.
Деревья состоят из папок device,vendor,kernel (иногда присутствуют не все).
В папке device присутствуют основные конфигурационные файлы, драйвера с открытым кодом и кое-что еще (обсудим позже).
В папке vendor- вся пропритетарщина (бинарные файлы с закрытым исходным кодом).В принципе их можно совать в device, но так правильнее.
В папке kernel – исходники ядра (А все файлы рамдиска в device!!!)
Часть 2
Сборочная система Андроид.Сейчас мы сделаем небольшое отступление, но без него Вам будет дальше трудно.
Делать деревья так сложно, потому что Андроид использует свою сборочную систему, основанную на make.
(Далее идет мой вольный перевод pdk(
http://www.kandroid.org/online-pdk/guide/build_system.html) со своими дополнениями и вырезаниями ненужного)
Вся система Андроид состоит из модулей. К каждому модулю прилагается makefile (Android.mk) в котором описано как собрать модуль.В android.mk указывается следующее:
1)Имя модуля (LOCAL_MODULE := <build_name>)
2)Очистка локальных переменных (include $(CLEAR_VARS))
3)Файлы исходного кода(LOCAL_SRC_FILES := main.c)
4)Теги(в каких сборках модуль будет присутствовать. Например только в сборках для разработчиков)( (LOCAL_MODULE_TAGS := eng development)
5)Библиотеки (какие библиотеки нам нужны)( LOCAL_SHARED_LIBRARIES := cutils)
6)Временный файл(include $(BUILD_EXECUTABLE))
Привожу пример Android.mk для модуля helloworld.
LOCAL_PATH := $(my-dir)\\устанавливаем директорию
include $(CLEAR_VARS)\\подключаем локальные переменные
LOCAL_MODULE := hello_world \\Название модуля
LOCAL_SRC_FILES := hello_world.c\\Файл с исходным кодом
LOCAL_MODULE_TAGS := eng \\Только для пользовательских сборок.
Уровни сборки.
Перейдем ближе к делу.
Есть 4 уровня сборки (от большого к малому)
1)Архитектура (Все устройства с одной архитектурой(armv6,armv7,x86,MIPS)
2)Плата (Все устройства с одинаковыми микросхемами и распайками)
3)Устройство(device)(Само устройство)
4)Продукт(product)(Модификации устройства, например, для разных стран)
На этом перевод заканчивается, начинается полет фантазии!
Часть 3
О драйверах.Перед тем, как начать делать дерево устройства, нам надо познакомиться с видами драйверов и конфигурационных файлов. Существует их 4 вида:
1)Переменные.
Им просто указывают значение и все. Пример-архитектура(грубо говоря, архитектура = «ваша архитектура»)
2)Конфигурационные файлы.
Это файлы, которые являются текстовыми и содержат разные параметры, нужные Андроиду.
Примеры:vold.fstab,egl.cfg.
3)Бинарные(пропритетарные) драйверы.
Драйверы устройств без исходного кода. Выковыриваются из стоковых прошивок и прошивок от похожих устройств.
4)open-source драйверы.
Драйверы с открытым исходным кодом. Мечта любого разработчика, ибо они легко приживаются к любому Андроиду. Их можно клянчить у производителей чипов (вряд ли дадут) или писать самим(почти нереально).Представляют собой отдельный модуль, кладутся в папку device.
Часть 5.
Делаем «костяк» дерева.Итак, наконец-то мы приступим к практике!
Сейчас вы сделаем основу будущего дерева.
Внимание! Все, что дальше, делать только под линуксом!!!
1)Создаем в любом месте папку device.
2)В ней создаем папку с названием производителя.
3)В папке с названием производителя создаем папку с названием устройства(Без цифр и спецзнаков! У каждого устройства есть такое название. Если не смогли найти-придумайте)
Получилась папка device/производитель/устройство.
4)В этой папке создадим файл vendorsetup.sh и пишем в него
add_lunch_combo имяустройста-eng
5)Создаем файл Android.mk(помните мы о нем говорили?) и пишем
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))
Этот файл подключит все файлы с расширением mk в данной директории.
6)Создаем файл AndroidProducts.mk и пишем:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/Имяустройства.mk
Важно! Перед 2 строкой должна быть табуляция, а не много пробелов!
7)Создаем файл Имяустройства.mk и пишем
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
PRODUCT_BRAND :=Производитель
PRODUCT_DEVICE :=Имяустройства
PRODUCT_NAME :=Имяустройства8)Создаем файл BoardConfig.mk и пишем: дальше ооочень внимательно.
TARGET_ARCH := arm (я пишу это руководство только для arm!X86 и mips делаются по-другому!)
TARGET_ARCH_VARIANT := архитектура.
Список возможных архитектур можно посмотреть в папке build/core/combo/arch/arm исходников по названия mk.
Про armv6:AOSP не поддерживает armv6.Лечится этим
патчем.TARGET_NO_KERNEL := true (пока ядро не собираем)
TARGET_CPU_VARIANT= (Возможные варианты: cortex-a7, cortex-a8, cortex-a9, cortex-a15, krait.Если у Вас другой процессор-пишите. Если у Вас другой процессор-пишите generic)
Если у Вас arm-v7, пишите
TARGET_CPU_ABI := armeabi-v7a
TARGET_CPU_ABI2 := armeabi
Если не armv7, то
TARGET_CPU_ABI := armeabi
9)Сохраняем это все и кидаем в корень исходников.
10)Компилируем. Описывать это не буду, на то есть куча статей.
Скорее всего, после этого прошивка не запустится, но все равно Вы это сделали! Вы – молодец!
Часть 6.
Добавляем пропритетарщину.В том каталоге, где создавали папку device,создаём папку vendor, в ней создаем папку с названием производителя, а в той - с названием устройства.
Получаем vendor/имяпроизводителя/имяустройства. Вот в ту папочку и идем. Затем кидаем туда все файлы, которые хотите скопировать в прошивку, сохраняя расположение. Пример:/lib/foo.so /lib/hw/foo.so /bin/foo.Наглядный пример
https://github.com/Whitexp/samsung-vendor-totoroЧто туда совать – ваше дело. Нужные файлы находятся методом тыка. НЕ КИДАЙТЕ ТУДА НИЧЕГО ИЗ app и framework. Для начала советую кинуть туда всю папку lib(кроме egl.cfg),etc,bin,usr.По мере продвижения процесса добавляйте и удаляйте файлы.
Затем идем в device/имяпроизводителя/имяустройства.Открываем файл имяустройства.mk и пишем в конец(для нашего примера)
PRODUCT_COPY_FILES += \
vendor/производитель/устройство/lib/foo.so:/system/lib/foo.so \
vendor/производитель/устройство/lib/hw/foo.so:/system/lib/hw/foo.so \
vendor/производитель/устройство/bin/foo:/system/bin/foo \
Надеюсь, суть вы поняли. Не забываем про табуляцию!
В device/имяпроизводителя/имяустройства кидайте egl.cfg и допишите BoardConfig.mk
BOARD_EGL_CFG := device/ имяпроизводителя/имяустройства/egl.cfg
Часть 7
Настраиваем экран
Дописываем в имяустройства.mk
PRODUCT_AAPT_CONFIG :=ldpi mdpi hdpi xhdpi
PRODUCT_AAPT_PREF_CONFIG := разрешение Вашего устройства (ldpi mdpi hdpi xhdpi)
PRODUCT_CHARACTERISTICS := (phone или tablet.Можно, не буду пояснять?)
Часть 8.
Займемся ядром.Для начала небольшое отступление. Хоть модули ядра лежат в рамдиске они все равно часть ядра. Скоро нам это понадобится.
Сборочная система Андроида позволяет собирать boot.img из файлов, которые Вы дали+автосгенерированные. Есть одно «но»: ядро и модули можно совать готовые, можно собрать из исходников в процессе сборки. Мною будут описаны оба способа, но я больше люблю второй.
Создадим папку kernel в ней папку с названием производителя, а в ней папку с названием устройства. Получаем kernel/производитель/имяустройства. Вот в эту папку закидываем исходники ядра так, чтобы Makefile лежал в корне этой папки.
Идем в папку device и дописываем в BoardConfig.mk
TARGET_KERNEL_SOURCE := kernel/производитель/имяустройства
TARGET_KERNEL_CONFIG := имяконфига_defconfig
Если не знаете, что такое конфиг и с чем его едят, читайте мою книгу, глава «Ядра»
Все это верно, если Вы идете по второму пути. Теперь пойдем по первому. Тут все еще проще.
Кладем в device/производитель/имяустройства ваш zImage и дописываем в BoardConfig.mk
TARGET_PREBUILT_KERNEL := device/производитель/имяустройства/zImage
Отлично! С ядром разобрались!
Остался рамдиск и упаковка.
Создаем в папке device/производитель/имяустройства папку ramdisk и кидаем туда то, что хотим засунуть в рамдиск(если компилируете из исходников, модули не нужны, если ядро готовое, то кидаем и модули) с сохранением названий директорий. Пример:
Ramdisk/modules/foo.ko
Ramdisk/ueventd.foo.rc
Теперь о том, что туда класть.
Класть туда НЕ НАДО файл init,init.rc,модули(если собираете из исходников ядро).Опять же: у Вас может быть по-другому. Подбирается экспериментально.
Теперь открываем имяустройства.mk и пишем в конце(для нашего примера)
PRODUCT_COPY_FILES += \
device/производитель/устройство/ramdisk/ueventd.foo.rc:root/ueventd.foo.rc \
device/производитель/устройство/ramdisk/modules/foo.ko:root/modules/foo.ko \
Осталось дописать параметры сборки boot.img.
Дописывем это в BoardConfig
BOARD_KERNEL_BASE := 0x81600000
BOARD_KERNEL_PAGESIZE := 4096
BOARD_PAGE_SIZE := 0x00001000
Значения этих переменных для вашего устройства можно посмотреть в разборщиках boot.img.
Ну вот и все…
Часть 9
Что дальше?
Есть большая вероятность, что это дерево не запустится, ибо я не мог предусмотреть тонкости для всех устройств и не мог описать всю сборочную систему. Мои советы, если не запускается:
1)Поиграйте с ядром. Чаще всего ошибка там.
2)Посмотрите файлы, которые Вы копируете через PRODUCT_COPY_FILES.Может вы что-то забыли или поставили лишнее?
3)Выложите ваше дерево на гитхаб и подключите максимальное количество разработчиков. Вместе-проще.
4)Посмотрите деревья других, похожих устройств и поищите различия.
5)(самое важное!)Не пишите мне об этом в QMS!!!Я физически не могу всем все править!!!Вы так можете в мой ЧС попасть!
Надеюсь,кому-нибудь поможет