PN Павлов Николай · технический блог Инженерный кейс · 2026

Android · LineageOS · Reverse Engineering · Display Stack

Xperia Z Ultra на Android 13

Один аппарат, 72 итерации образа, восстановленный Sony UI и измеренная стабилизация графического тракта, Google runtime и экрана недавних приложений.

Sony C6833 / togari LineageOS 20 Snapdragon 800 / Adreno 330
16,7 мс p95 прокрутки Passenger Control после исправления
0,45% проблемных кадров в тесте окна настроек
83-91 мс горячий запуск Recents после исправления lifecycle
Рабочий стол Xperia Home на Sony Xperia Z Ultra с фирменными обоями
Обложка / live capture. Фактический кадр рабочего стола на C6833 после прошивки v72.

Аннотация

Проект показал, что визуальную идентичность старой Xperia можно вернуть на Android 13 без переноса несовместимого Sony SystemUI. Однако на платформе msm8974 внешний вид нельзя отделить от композиции кадров: прозрачность, затемнение и смена ориентации напрямую определяют нагрузку на HWC, MDP и GLES.

Финальный образ
LineageOS 20 v72 + runtime v1.3
Экран
1080 × 1920, 60 Гц
Композиция
HWC2 / MDP + GLES
Root
Magisk 30.7
v38 Стабильная загрузка Android 13 и исправленный системный стек.
v40 Интеграция Xperia Home и фирменного визуального слоя.
v44 Полная перерисовка кадров для борьбы с краевыми артефактами.
v64 Шторка, яркость, параллакс обоев и геометрия keyguard.
v71 Селективная HWC-политика и непрозрачная подложка шторки.
v72 Точечный MDP-путь Passenger Control и финальная валидация.
post-v72 Привилегированный Google runtime и коррекция lifecycle отдельного Quickstep.
01 / Платформа

Современный framework на аппаратуре 2013 года

Главное ограничение проекта задавал не Android 13 сам по себе, а взаимодействие нового оконного стека со старым графическим драйвером Qualcomm.

Xperia Z Ultra C6833 построен на Snapdragon 800, оснащён 2 ГБ RAM и GPU Adreno 330. Физический дисплей работает в режиме MIPI-DSI video с разрешением 1080 × 1920 при 60 Гц. Следовательно, новый кадр должен быть подготовлен примерно за 16,67 мс.

LineageOS 20 переносит на аппарат современный SurfaceFlinger, WindowManager и SystemUI. Но vendor-часть остаётся наследием msm8974. Между ними работает совместимый HWC-слой, который решает, какие поверхности можно отдать аппаратным плоскостям MDP, а какие нужно предварительно собрать GPU в единый client target.

Проблема проявлялась не как одна ошибка. Пользователь видел тормоза при закрытии шторки, задержки в меню, нестабильный ползунок яркости, белую или чёрную область в правом нижнем углу, а также тяжёлые переходы при смене ориентации. Эти симптомы оказались разными выходами одной системы: политика композиции, синхронизация поверхностей и фоновая нагрузка на system_server.

Узел Конфигурация Инженерное значение
Устройство Sony Xperia Z Ultra C6833, togari ARM32, 2 ГБ RAM, старый bootloader Sony
SoC Qualcomm Snapdragon 800 / msm8974 Ограниченный запас CPU и пропускной способности памяти
GPU Adreno 330 Чувствительность к полному GLES-композитингу 1080p
Панель sharp renesas 1080p video new id 1080 × 1920 при 60 Гц, MIPI-DSI video
Тач MAX1187x, I2C 0x48 Отдельная проверка геометрии жестов в портрете и landscape
Система LineageOS 20 / Android 13 Новый SystemUI поверх legacy vendor stack
02 / Визуальный слой

Реконструкция Sony UI вместо пересадки старого SystemUI

Старый системный APK Android 5.1 несовместим с framework Android 13. Поэтому перенос выполнен на уровне ресурсов, геометрии и новых компонентов.

Экран блокировки Sony 5.1 использовал старые private API, ODEX, signature-разрешения и механизм Runtime Skinning. Прямая установка такого SystemUI.apk на Android 13 привела бы к циклическому падению интерфейса. Вместо этого крупные двухъярусные часы Xperia были реализованы внутри современного Keyguard, сохранив актуальные механизмы PIN, уведомлений и системной безопасности.

Геометрия рассчитывалась не по физической диагонали, а по фактической плотности и доступной области экрана. В портрете часы занимают визуальный центр верхней половины. В landscape отдельная раскладка учитывает системную навигационную полосу: в финальной ветке центр замка задан по ширине content area 1824 px, то есть x = 912 px.

Рис. 1. Контрольная реализация Xperia-keyguard в портретной ориентации.
Рис. 2. Отдельная landscape-компоновка, проверенная на разрешении 1920 × 1080.
Рис. 3. Шторка в landscape. Сенсорная зона ползунка яркости отделена от перехода в приложение настроек.

Xperia Home и меню приложений

Оригинальный Home 5.1 также нельзя было переносить побайтово. В основу взят более новый Xperia Home, совместимый с Android 13. В нём сохранена логика рабочего стола и локальная миграция настроек, отключены необязательные аналитические точки запуска, а визуальные ресурсы меню приложений заменены материалами C6833.

Стоковый набор использовал 56dp-иконки и 15sp-подписи для профиля sw360dp. Но итоговая сетка вычисляется современным launcher-кодом для текущей плотности. Это визуальная реконструкция, а не запуск бинарного Sony Home из прошивки 14.6.A.1.236.

Рис. 4. Центральная страница рабочего стола.
Рис. 5. Соседняя страница. Смещение фонового рисунка подтверждает параллакс.
Рис. 6. Меню приложений после переноса Xperia-ресурсов.

Стоковый набор обоев и медиа

Из эталонной прошивки C6833 14.6.A.1.236 извлечены полноразмерные обои, миниатюры, UI-звуки и загрузочная анимация 1080 × 1920. Источником FTF было стороннее зеркало, поэтому корректная формулировка здесь важна: совпадают модель и номер сборки, но принадлежность ресурсов прежнему региональному пакету не доказана официальной подписью Sony.

Обои Xperia Air Синие обои Xperia Flow Пурпурные обои Xperia Flow Обои Xperia Silk Светлые обои Xperia Обои Xperia Heat
03 / Методика

Диагностика по слоям, кадрам и журналам

Субъективное ощущение лагов использовалось как триггер, но решение принималось только после сопоставления нескольких независимых измерений.

На 60-герцовом дисплее один период развёртки составляет 16,67 мс. Интервал свыше 33 мс уже означает пропуск как минимум одного периода. Но gfxinfo описывает работу приложения, а временная шкала SurfaceFlinger отражает вывод композиции на дисплей. Поэтому эти метрики нельзя механически складывать или подменять одной другой.

Каждая гипотеза проверялась повторяемым жестом, очисткой статистики перед серией, снимком HWC-состава во время проблемного состояния и кадрами, захваченными непосредственно в переходе. После теста отдельно проверялись ANR, crash и FATAL-события.

dumpsys gfxinfo Кадры приложения

FrameStats, p50, p90, p95, p99 и доля modern jank.

dumpsys SurfaceFlinger Фактическая композиция

DEVICE или CLIENT, client target, слои и интервалы вывода.

logcat + events Системные события

ANR, перезапуски, FATAL, HWC-ошибки и блокировки WindowManager.

screencap Пространственный контроль

Серия кадров во время жеста для поиска чёрного или белого угла.

Графический конвейер Android на Xperia Z Ultra Поверхности приложений и SystemUI поступают в SurfaceFlinger. Простые непрозрачные слои выводятся через MDP, сложные эффекты собираются GLES и затем передаются на дисплей. ИСТОЧНИКИ ПОВЕРХНОСТЕЙ Приложение buffer layer / dialog / wallpaper SystemUI shade / bars / effect layer SurfaceFlinger проверка геометрии, alpha и transform выбор DEVICE или CLIENT MDP / DEVICE аппаратные плоскости, низкая цена кадра GLES / CLIENT TARGET GPU предварительно собирает полный кадр 1080p @ 60 Гц
04 / Графический тракт

Почему угол мигал чёрным, а затем белым

Артефакт возникал на границе режимов композиции, когда полупрозрачная поверхность меняла состав кадра быстрее, чем legacy HWC стабильно перестраивал плоскости.

Первые попытки лечить мигающий угол полным переводом сцены в GLES устраняли часть повреждённых кадров, но резко увеличивали время рендеринга. Обратная крайность, принудительный MDP для любой поверхности, ломала эффекты, которые аппаратные плоскости не могли корректно представить.

Рабочая политика появилась после разделения слоёв по назначению. Обычные непрозрачные окна, рабочий стол и закрывающаяся шторка оставались на MDP. Только эффектные и dim-слои получали GLES fallback. При смене ориентации HWC-кэш обновлялся, а формат поверхности SystemUI не менялся в терминальном кадре закрытия.

В v71 подложка шторки стала непрозрачной, но живой launcher под ней сохранился. Это убрало чёрный полноэкранный буфер при закрытии и не уничтожило параллакс обоев. В проверке v72 шесть последовательных кадров закрытия не содержали ни чёрного, ни белого промежуточного экрана.

0 / 6 кадров закрытия с чёрным или белым промежуточным экраном
10,73% modern jank SystemUI в пяти циклах шторки
DEVICE нормальные непрозрачные поверхности в контрольной сцене
MDP + GPU смешанная композиция вместо постоянного полного GLES
05 / Прикладной кейс

Passenger Control: 483 мс превратились в 16,7 мс

Окно настроек автомобильного приложения стало стресс-тестом для всей графической архитектуры.

Passenger Control 1.40.0-beta13 открывает большое дополнительное окно с полупрозрачным системным затемнением позади. На msm8974 один HWC2 solid-color dim effect между двумя buffered windows переводил весь дисплей в legacy GLES client target. В v71 прокрутка настроек давала p50 около 300 мс и p95 около 483 мс. Одновременно появлялся белый или чёрный угол.

Глобальное отключение dim было бы неправильным: оно изменило бы поведение всех приложений. В v72 условие помещено в WindowState.applyDims() и ограничено пакетом ru.monjaro.passengercontrol.client. Для остальных окон Android логика затемнения не меняется.

final boolean suppressPassengerControlDim =
    "ru.monjaro.passengercontrol.client".equals(mAttrs.packageName);

if (!suppressPassengerControlDim
        && ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
        || shouldDrawBlurBehind())
        && isVisibleNow() && !mHidden) {
    // Стандартный системный dim для остальных окон
}
Время кадра Passenger Control до и после исправления В v71 медиана равнялась примерно 300 миллисекунд, а 95-й процентиль 483 миллисекундам. В v72 оба показателя равны 16,7 миллисекунды. Время кадра, мс Меньше лучше. Бюджет одного кадра при 60 Гц равен 16,67 мс. 0 100 200 300 400 500 300 483 16,7 16,7 v71 p50 v71 p95 v72 p50 v72 p95 16,67 мс

Серия v72: 12 прокруток, 126 интервалов SurfaceFlinger, один интервал свыше 33 мс; gfxinfo зафиксировал 2 проблемных кадра из 441.

Рис. 7. Главное окно Passenger Control. В контрольной сцене основное окно, дополнительное окно и системные полосы представлены четырьмя слоями DEVICE, usesClientComposition=false.
Рис. 8. Климат.
Рис. 9. Сиденья.
Рис. 10. Главный раздел.
06 / ANR и фоновые процессы

Исправление запоздалого ANR не должно само создавать лаги

Системная защита и Magisk-сценарий были переработаны как единый контур, потому что резервные копии скрипта неожиданно стали частью проблемы.

Исходный дефект заключался в гонке: приложение успевало восстановить обработку ввода, но уже подготовленное сообщение о показе ANR-диалога оставалось в очереди UI Handler. В framework введён токен конкретного ANR-события. Когда input dispatch возобновляется, токен, отложенное сообщение и видимый диалог очищаются атомарно. Устаревшее сообщение больше не может воскресить завершившийся ANR.

Дополнительный root-сценарий служит ограниченной страховкой. Он подписывается на am_anr, открывает 75-секундное окно частых проверок и выбирает только кнопку Wait по resource id aerr_wait. Принудительное закрытие, очистка данных и изменение пакета не выполняются.

После прошивки выяснилось, что Magisk исполнял не только основной файл, но и три резервные копии .bak-*, оставленные внутри /data/adb/service.d. В результате появилось 12 лишних процессов, а две старые копии вызывали дорогой dumpsys window каждую секунду. Binder-нагрузка system_server достигала примерно 31%.

  1. Исполняемые backup-файлы Magisk просматривает service.d и запускает все подходящие скрипты.
  2. Дублированные мониторы Главный файл и три копии создают 12 дополнительных процессов.
  3. WindowManager под опросом Два dumpsys window в секунду занимают binder-потоки system_server.
  4. Задержка UI Финальные фазы свайпа и возврата на рабочий стол теряют кадры.

Исправление

Резервные копии были обратимо перенесены в /data/adb/togari-script-backups/20260827-anr-autowait, завершены только процессы с точным совпадением командной строки, а основной скрипт получил singleton-lock через атомарное создание каталога. После этого доля CPU у system_server снизилась примерно до 3,1%.

Финальный стресс-тест включал 30 быстрых перелистываний Xperia Home. gfxinfo показал 701 кадр, 0 modern jank и 0 legacy jank; p50, p90, p95 и p99 составили 9, 9, 10 и 11 мс. SurfaceFlinger при этом зарегистрировал три интервала свыше 33 мс из 125, поэтому корректный вывод звучит как устранение регулярного launcher-лага, а не обещание математически идеального вывода.

31 → 3,1% наблюдаемая CPU-доля system_server
30 быстрых перелистываний рабочего стола
0 / 701 modern и legacy jank по gfxinfo
p99 11 мс время кадра приложения launcher
07 / Google runtime и Recents

Два системных дефекта выглядели как один общий тормоз

Падение Google Play было вызвано неполным набором привилегированных сервисов, а тяжёлый экран недавних приложений зависел от отдельного Quickstep и незавершённого анимационного handoff.

Google Play: восстановление системного контракта

В исходном состоянии Play Store завершался с ошибкой Failed to load configurations for FinskyApp. В журнале отсутствовал provider com.google.android.gsf.gservices. Это указывало не на сетевой сбой и не на повреждение пользовательских данных, а на отсутствие Google Services Framework и согласованного привилегированного окружения для Play Services и Phonesky.

Для частного устройства собран Magisk-модуль togari_minimal_gapps v1.3. Он монтирует Google Services Framework в system_ext/priv-app, GmsCore и Phonesky в product/priv-app, а также добавляет соответствующие privapp-permissions, default-permissions и sysconfig. После перезагрузки PackageManager распознал все три пакета как SYSTEM и PRIVILEGED; разрешения MANAGE_USERS, INTERACT_ACROSS_USERS и READ_DEVICE_CONFIG выданы. Контрольный запуск дошёл до AssetBrowserActivity, а в окне проверки не было FATAL, crash или ANR для Play Store.

  1. Sony Home Рабочий стол остаётся приложением по умолчанию и отвечает за Xperia UI.
  2. Кнопка Recents Системный жест передаётся не Sony Home, а отдельному Quickstep.
  3. Launcher3 Quickstep com.android.quickstep.RecentsActivity собирает полноразмерные task snapshots.
  4. Surface handoff Завершённая анимация освобождает recents surface и возвращает композицию Home.

Почему нулевая анимация оказалась медленнее

В проверяемой конфигурации Sony Home был default launcher, но экран недавних приложений обслуживал com.android.launcher3/com.android.quickstep.RecentsActivity. При значениях window_animation_scale=0 и transition_animation_scale=0 визуальная часть перехода исчезала, однако recents animation input consumer и связанные поверхности иногда оставались активными уже после возврата Home. В таком состоянии SurfaceFlinger продолжал занимать примерно 80-118% одного CPU, поэтому последующие переходы выглядели всё тяжелее.

Все три коэффициента анимации установлены в 0,5. Это не декоративная мера, а восстановление времени, необходимого WindowManager и Quickstep для штатного завершения протокола перехода. После закрытия Recents рабочий стол снова становится resumed activity, а нагрузка SurfaceFlinger через несколько секунд возвращается к 0%. Прямые прогретые запуски дали 91 и 83 мс; первый запуск уже поднятого сервиса занял 292 мс.

3 пакета GSF, GmsCore и Phonesky восстановлены как системные
0 FATAL в контрольном запуске Google Play после исправления
83-91 мс два горячих запуска отдельного RecentsActivity
0,5 / 0,5 / 0,5 window, transition и animator scale

Фоновая нагрузка как независимый фактор

Отдельный эксперимент локализовал ещё один источник деградации. При активном Яндекс Диске его три процесса занимали около 300 МБ resident memory, основной процесс потреблял примерно 25-85% CPU, а доступная память снижалась примерно до 86 МБ. В журналах одновременно наблюдались запуск Activity за 5,239 с, pause timeout и обработка focus event продолжительностью 3096 мс. После обратимого force-stop SurfaceFlinger вернулся к 0% в покое, а свободная память выросла примерно до 195 МБ.

Автосинхронизация Яндекс Диска не отключалась и фоновые ограничения пакета не менялись. Поэтому повторное открытие приложения может снова создать нагрузку. Этот фактор нельзя смешивать с исправлением Quickstep: он подтверждает, что на устройстве с 2 ГБ RAM один тяжёлый клиент способен исчерпать запас памяти и пропускной способности всей графической системы.

08 / Системный образ

Один блок ART потребовал корректной хирургии ext4

Изменение framework было мало написать и скомпилировать. Его нужно было поместить в Sony-совместимый sparse image без повреждения ext4.

Патч v72 изменил services.jar и соответствующие AOT-артефакты. Новый services.art оказался ровно на один блок 4096 байт больше прежнего extent. Обычная замена файла нарушила бы размещение следующих данных или метаданные файловой системы.

Скрипт v72-extend-services-art.py использовал debugfs fallocate, сопоставил логический блок 515 со свободным физическим блоком 408246, обновил ext4 metadata и добавил соответствующий RAW-chunk в sparse-поток. После упаковки проверены SELinux xattr, e2fsck -fn и точное совпадение sparse-to-raw round trip.

  1. Новый framework services.jar, art, odex и vdex собираются согласованным набором.
  2. Расширение extent Логический блок 515 получает свободный физический блок 408246.
  3. Sony sparse Новый RAW-chunk вставляется без повторного преобразования старым bootloader.
  4. Верификация xattr, e2fsck, SHA-256 и побайтовый raw round trip.
system-v72.img a9ecbbb13a4832e3ce2acf34ec9cf2670ed09fd2115be1952fcd1feab09a67dc
raw-развёртка db1a92c6b1530d71252648dae9100a28e869fdf4d257bec5729e7d9005f42056
HWC v71 в составе v72 16ea8a4436b8719ed3b8069b4a763383968b51940006385c915055d96b5b286d
services.jar 51978cfcbb44a2040117e996e3c8a97d00016e101429a6350a5d3e19e15cd514
services.art 600dd1ed1a3c8adc99c616b9037db8d222eb8b97b5db666b9adfc99d2d014175
services.odex 83cc66666d146c64f255afe61ca98e69a3950b69f14a37ace0d8364ec81c2121
services.vdex 16835f476f1e87293f77993cf078b4d478071acd4224c7275f9e2b59dc7d00a4
09 / Итоги испытаний

Что подтверждено на физическом C6833

Таблица отделяет проверенные результаты от остаточных ограничений. Это важнее формулировки «всё быстро».

Подсистема Проверка Результат Статус
Загрузка Фактическая прошивка system-v72.img sys.boot_completed=1, стабильный запуск Подтверждено
Passenger Control 12 прокруток окна настроек p50/p95 16,7 мс; 2/441 jank, 0,45% Подтверждено
Графический артефакт 8 mid-scroll кадров Passenger Control Чёрный или белый угол не обнаружен Подтверждено
Страницы приложения 5 разделов, без команд автомобилю 15 переходов, 1/30 jank, 3,33% Подтверждено
Xperia Home 30 быстрых свайпов после service.d fix 0/701 jank; p95 10 мс; параллакс работает Подтверждено
Google Play Привилегированный runtime v1.3 и контрольный запуск GSF provider доступен; AssetBrowserActivity работает; новых FATAL нет Подтверждено
Recents Отдельный Quickstep, scale 0,5 и возврат на Home Горячие запуски 91 и 83 мс; поверхность завершается штатно Подтверждено
Холодный Recents Первый запуск поднятого сервиса 292 мс; snapshots сохраняют полное разрешение Ограничение
Закрытие шторки 6 последовательных переходных кадров Чёрный или белый полноэкранный кадр не обнаружен Подтверждено
SystemUI 5 циклов шторки 19/177 modern jank, 10,73% Ограничение
Ориентация Портрет и landscape Геометрия исправлена, переход всё ещё может выглядеть тяжёлым Ограничение
Root Magisk su uid=0, контекст u:r:magisk:s0 Подтверждено
Сеть Wi-Fi после загрузки Интерфейс включён и подключён Подтверждено
Стабильность Журналы после финального теста Новых ANR, am_crash и FATAL нет Подтверждено
Не полная копия Sony 5.1

Современные безопасность, bouncer и lifecycle сохранены. Старые бинарные компоненты Sony не запускаются.

Не абсолютные 60 fps

Adreno 330 и 2 ГБ RAM остаются физическим пределом. Редкие длинные интервалы SurfaceFlinger возможны.

Ориентация остаётся дорогой

Перестройка буферов 1080p и HWC-кэша заметнее обычных переходов, особенно под нагрузкой.

Фоновые клиенты всё ещё критичны

Яндекс Диск не ограничен постоянно. Его повторный запуск способен вернуть дефицит RAM и общесистемные задержки.

10 / Вывод

Реставрация интерфейса оказалась задачей системной инженерии

Xperia Z Ultra удалось вернуть визуальный язык Sony и одновременно сохранить Android 13. Ключ к результату был не в тотальном ускорении и не в глобальном отключении эффектов, а в локальных правилах: правильный слой отправляется в правильный композитор, конкретный ANR получает собственный токен, Google runtime восстанавливается согласованным набором, а Quickstep получает время для корректного завершения lifecycle.