Android

Как обновить ядро Android до последней стабильной версии Linux

Мы уже рассматривали руководства по ядрам Android, такие как «Как собрать пользовательское ядро» и «Лучшие пользовательские ядра для Android«, но сегодня мы покажем вам, как обновить ядро до последней стабильной версии Linux.

Пожалуйста, знайте, что это продвинутый материал — если вы никогда раньше не компилировали ядро, вам следует следовать руководству «How to Build a Custom Kernel», ссылка на которое приведена выше, и это руководство включает в себя выборку и слияние коммитов из последнего стабильного ядра Linux с вашим ядром Android, прежде чем вы его скомпилируете.

Обновление ядра Android до последней стабильной версии Linux имеет много положительных преимуществ, например, обновление до последних фиксаций безопасности и исправлений ошибок — мы объясним некоторые плюсы и минусы далее в этом руководстве.

Что такое Linux-Stable kernel?

Linux-stable, как следует из названия, является стабильной версией ядра Linux. Другой рычаг известен как «магистральный», который является основная ветвь. Вся разработка ядра Linux происходит в mainline и в целом следует этому процессу:

  1. Линус Торвальдс будет принимать кучу патчей от своих сопровождающих в течение двух недель.
  2. После этого через две недели он выпускает rc1 (e.g. 4.14-rc1) kernel.
  3. Каждую неделю в течение следующих 6-8 недель он будет выпускать очередной RC (e.g. 4.14-rc2, 4.14-rc3 и т.д.) ядра, которое содержит ТОЛЬКО исправления ошибок и регрессий.
  4. Как только ядро будет признано стабильным, оно будет выпущено в виде tarball для загрузки на сайте org(e.g. 4.14).

Что такое ядра LTS?

Каждый год Грег будет выбирать одно ядро и поддерживать его либо два года (LTS), либо шесть лет (расширенный LTS). Они предназначены для продуктов, которым необходима стабильность (например, телефоны Android или другие IOT-устройства). Процесс точно такой же, как и выше, просто он происходит в течение более длительного времени. В настоящее время существует шесть ядер LTS (которые всегда можно посмотреть на сайте ядро.страница релизов org):

  • 4.14 (LTS), поддерживается Грегом Кроа-Хартманом
  • 4.9 (LTS), поддерживается Грегом Кроа-Хартманом
  • 4.4 (eLTS), поддерживается Грегом Кроа-Хартманом
  • 4.1(LTS), поддерживается Сашей Левиным
  • 3.16 (LTS), поддерживается Беном Хатчингсом
  • 3.2 (LTS), поддерживается Беном Хатчингсом

Какие преимущества дает обновление ядра Android до Linux Stable?

Когда раскрываются/исправляются важные уязвимости, стабильные ядра получают их первыми. Таким образом, ваше ядро Android будет гораздо более безопасным в отношении атак, недостатков безопасности и просто ошибок в целом.

Стабильная версия Linux включает исправления для множества драйверов, которые мое устройство Android не использует, не является ли это в основном ненужным?

Да и нет, в зависимости от того, как вы определяете слово «в основном». Ядро Linux может включать много кода, который не используется в системе Android, но это не гарантирует, что при объединении новых версий не возникнет конфликтов из-за этих файлов! Поймите, что практически никто собирает все части ядра, даже самые распространенные дистрибутивы Linux, такие как Ubuntu или Mint. Это не означает, что вы не должны принимать эти исправления, потому что там СТАТЬ исправления для драйверов DO запустить. Возьмем для примера arm/arm64 и ext4, которые являются наиболее распространенными архитектурой и файловой системой Android соответственно. В 4.4, от 4.4.78 (версия последней версии Oreo CAF tag) до 4.4.121 (последняя метка upstream), это следующие номера коммитов этих систем:

nathan@flashbox ~/kernels/linux-stable (master) $ git log --format=%h v4.4.78..v4.4.121 | wc -l2285 nathan@flashbox ~/kernels/linux-stable (master) $ git log --format=%h v4.4.78..v4.4.121 arch/arm | wc -l58 nathan@flashbox ~/kernels/linux-stable (master) $ git log --format=%h v4.4.78..v4.4.121 arch/arm64 | wc -l22 nathan@flashbox ~/kernels/linux-stable (master) $ git log --format=%h v4.4.78..v4.4.121 fs/ext4 | wc -l18

Наиболее трудоемкой частью является первоначальное внедрение; как только вы полностью обновляетесь, слияние в новый релиз, который обычно содержит не более 100 коммитов, не занимает много времени. Преимущества, которые это дает (большая стабильность и лучшая безопасность для ваших пользователей), должны вызвать необходимость этого процесса, хотя.

Как объединить стабильное ядро Linux с ядром Android

Сначала необходимо выяснить, какая версия ядра установлена на вашем устройстве Android.

Как бы банально это ни казалось, необходимо знать, с чего начать. Выполните следующую команду в вашем дереве ядра:

make kernelversion

Это вернет вам версию, на которой вы находитесь. Первые два числа будут использоваться для определения нужной вам ветки (e.g. linux-4.4.y для любого 4.4 kernel), а последнее число будет использоваться для определения того, с какой версии вам нужно начать слияние (e.g. если вы находитесь на 4.4.21, вы ’объедините 4.4.22 далее).

Возьмите последний исходный код ядра из kernel.org

kernel.org установите дома последний исходный код ядра репозиторий linux-stable. Внизу страницы будут три ссылки на выборку. По моему опыту, зеркало Google’ имеет тенденцию быть самым быстрым, но ваши результаты могут варьироваться. Выполните следующие команды:

git remote add linux-stable https://kernel.googlesource.com/pub/scm/linux/kernel/git/stable/linux-stable.gitgit fetch linux-stable

Решите, хотите ли вы объединить все ядро или выбрать отдельные коммиты

Далее вам нужно выбрать, хотите ли вы слить все коммиты или выбрать только те, которые вам нужны. Вот ’плюсы и минусы каждого из них, и когда вы можете захотеть их сделать.

ПРИМЕЧАНИЕ: Если ваш исходный код ядра находится в виде tarball, вам, скорее всего, придется делать cherry-pick, иначе вы получите тысячи конфликтов файлов, поскольку git заполняет историю, основываясь исключительно на upstream, а не на том, что изменил OEM или CAF. Просто перейдите к шагу 4.

Выборка по принципу «вишни»:

Плюсы:

  • Легче разрешать конфликты, так как вы точно знаете, какой конфликт вызывает проблему.
  • Легче перебазировать, так как каждый коммит является самостоятельным.
  • Легче разделить на части, если возникнут проблемы

Конс:

  • Это занимает больше времени, так как каждый коммит должен быть выбран индивидуально.
  • Немного сложнее с первого взгляда определить, является ли коммит из апстрима

Объединить

Плюсы:

  • Это ’быстрее, так как вам не нужно ждать, пока все чистые патчи сольются.
  • Легче определить, когда коммит сделан из апстрима, поскольку коммиттером будете не вы, а мейнтейнер апстрима.

Минусы:

  • Разрешение конфликтов может быть немного сложнее, так как вам нужно будет искать, какой коммит вызвал конфликт, используя git log/git blame, он не скажет вам об этом напрямую.
  • Перезаливка сложна, так как вы не можете переделать слияние, оно предложит вам выбрать все коммиты по отдельности. Тем не менее, вам не следует часто выполнять ребазинг, вместо этого используйте git revert и git merge, где это возможно.

Я бы порекомендовал сначала сделать cherry-pick для выявления любых проблемных конфликтов, выполнить слияние, а затем вернуть проблемные коммиты, чтобы обновление было проще (так как слияние происходит быстрее после обновления).

Добавьте коммиты к вашему источнику, по одной версии за раз

Наиболее важной частью этого процесса является часть, касающаяся одной версии за раз. В вашей серии апстримов МОЖЕТ быть проблемный патч, который может вызвать проблемы с загрузкой или сломать что-то вроде звука или зарядки (объясняется в разделе советы и рекомендации). Делать инкрементные изменения версии важно по этой причине, легче найти проблему в 50 коммитах, чем в 2000 коммитах для некоторых версий. Я бы рекомендовал выполнять полное слияние только после того, как вы узнаете все проблемные коммиты и разрешения конфликтов.

Сбор вишенок

Формат:

git cherry-pick <previous_tag>..<следующий_тег>

Пример:

git cherry-pick v3.10.73..v3.10.74

Объединить

Формат:

git merge <next_tag>

Пример:

git merge v3.10.74

Я рекомендую отслеживать конфликты в коммитах слияния, удаляя #-маркеры.

Как разрешить конфликты

Мы не можем дать пошаговое руководство по разрешению каждого конфликта, так как это требует хорошего знания языка C, но вот несколько подсказок.

Если вы сливаетесь, выясните, какой коммит вызывает конфликт. Вы можете сделать это одним из двух способов:

  1. git log -p v$(make kernelversion)..<latest_tag> чтобы получить изменения между вашей текущей версией и последней версией из восходящего потока. Флаг -p предоставит вам изменения, сделанные каждым коммитом, так что вы сможете увидеть.
  2. Выполните git blame для файла, чтобы получить хэши каждого коммита в этой области. Затем вы можете выполнить git show –format=fuller, чтобы узнать, был ли коммиттер из mainline/stable, Google или CodeAurora.
  • Выяснить, есть ли у вас уже этот коммит. Некоторые поставщики, такие как Google или CAF, пытаются искать критические ошибки, например, исправление Dirty COW, и их бэкпорты могут конфликтовать с бэкпортами из Upstream’. Вы можете запустить git log –grep=”<part_of_commit_message>” и посмотреть, вернется ли что-нибудь. Если это так, вы можете пропустить коммит (если вы собираете вишни с помощью git reset –hard && git cherry-pick –continue) или проигнорировать конфликты (удалить <<<<<< и всего, что находится между ====== и >>>>>>).
  • Выясните, не был ли сделан бэкпорт, который нарушает разрешение. Google и CAF любят бэкпортировать некоторые исправления, которые стабильные компании не стали бы делать’. В Stable часто требуется адаптировать разрешение основного коммита к отсутствию некоторых исправлений, которые Google предпочитает бэкпортировать. Вы можете посмотреть на основной коммит, выполнив git show <хэш> (хэш mainline будет доступен в сообщении о коммите стабильного коммита). Если есть бэкпорт, который всё испортил, вы можете либо отбросить изменения, либо использовать основную версию (что обычно и нужно делать).
  • Прочитайте, что пытается сделать коммит, и посмотрите, не исправлена ли уже проблема. Иногда CAF может исправить ошибку независимо от upstream, что означает, что вы можете либо переписать их исправление на upstream’, либо отменить его, как описано выше.

В противном случае, это может быть просто результат добавления CAF/Google/OEM, в этом случае вам просто нужно перетасовать некоторые вещи.

Вот зеркало ядра linux-stable.org repository на GitHub, что может быть проще для поиска списков коммитов и дифов для разрешения конфликтов. Я рекомендую сначала перейти к просмотру списка коммитов и найти проблемный коммит, чтобы увидеть оригинальное отличие и сравнить его с вашим.

Пример URL: https://github.com/nathanchance/linux-stable/commits/linux-3.10.y/arch/arm64/mm/mmu.c

Вы также можете сделать это через командную строку:

git log <текущая_версия>..<version_being_added> <путь>
git show <hash>

Решение проблем зависит от контекста. Что вы должны делать ВСЕГДА, так это убедиться, что ваш окончательный diff совпадает с upstream’, выполнив следующие команды в двух отдельных окнах:

git diff HEAD
git diff v$(make kernelversion)..$(git tag --sort=-taggerdate -l v$(make kernelversion | cut -d . -f 1,2)* | head -n1)

Включить рерайт

Git имеет функцию под названием rerere (расшифровывается как Reuse Recorded Resolution), что означает, что когда он обнаружит конфликт, он запишет, как вы его разрешили, чтобы вы могли использовать его позже. Это особенно полезно для хронических репостов как с объединением, так и с виш-пикингом, поскольку вам нужно будет просто выполнить git add . && git <merge|cherry-pick> – продолжать при повторном обновлении, так как конфликт будет разрешен так, как вы разрешили его ранее.

Его можно включить, выполнив следующую команду в вашем репозитории ядра:

git config rerere.enabled true

Как сделать git bisect при ошибке компилятора или времени выполнения

Учитывая, что вы добавляете значительное количество коммитов, вполне возможно, что вы внесете ошибку компилятора или времени выполнения. Вместо того чтобы просто сдаться, вы можете использовать встроенный в git’ инструмент bisect, чтобы выяснить первопричину проблемы! В идеале, вы будете собирать и прошивать каждую версию ядра по мере добавления, поэтому сокращение займёт меньше времени, но вы можете сократить 5000 коммитов без каких-либо проблем.

git bisect сделает следующее: возьмет диапазон коммитов, от того, где проблема присутствует, до того, где ее не было, а затем начнет сокращать диапазон коммитов вдвое, позволяя вам собрать и протестировать и сообщить, хорошо это или нет. Это будет продолжаться до тех пор, пока он не выплюнет коммит, вызвавший вашу проблему. В этот момент вы можете либо исправить его, либо вернуть на место.

  1. Начните биссектирование: git bisect start
  2. Пометьте текущую ревизию как плохую: git bisect bad
  3. Пометить ревизию как хорошую: git bisect good <sha1>
  4. Сборка с новой ревизией
  5. Исходя из результата (есть проблема или нет), скажите git: git bisect good OR git bisect bad
  6. Промывайте и повторяйте шаги 4-5, пока не будет найден проблемный коммит!
  7. Верните или исправьте проблемный коммит.

ПРИМЕЧАНИЕ: При слиянии нужно будет временно выполнить git rebase -i <good_sha> чтобы применить все исправления к вашей ветке для правильного биссектирования, так как при биссектировании с уже существующими слияниями часто происходит выгрузка на коммиты восходящего потока, что означает, что у вас нет коммитов, специфичных для Android. Я могу более подробно рассказать об этом по запросу, но поверьте мне, это необходимо. Как только вы определили проблемный коммит, вы можете вернуть или перебазировать его в слияние.

НЕ удаляйте обновления из восходящего потока

Многие новые разработчики склонны поступать именно так, поскольку это “чище” и “проще” в управлении. Это ужасно по нескольким причинам:

  • Авторство теряется. Это несправедливо по отношению к другим разработчикам, когда их заслуги не учитываются в их работе.
  • Биссектриса невозможна. Если вы сминаете серию коммитов и что-то в этой серии вызывает проблему, невозможно определить, какой коммит вызвал проблему в сминаемом коммите.
  • Будущие ревизии сложнее. Если вам нужно сделать ребазинг со скомканной серией, трудно/невозможно определить, где возник конфликт.

Подпишитесь на список рассылки Linux Kernel для получения своевременных обновлений

Чтобы получать уведомления о каждом обновлении, подпишитесь на рассылку список анонсов linux-kernel-announce. Это позволит вам получать электронное письмо каждый раз, когда выходит новое ядро, чтобы вы могли обновлять и устанавливать его как можно быстрее.

Добавить комментарий