Эта статья родилась из практической задачи — понять, как устроен Android в общем и целом, как он сохраняет и восстанавливает состояния приложения (помимо БД и файлов) при внезапном завершении процесса, как управляет процессами. Знание этих механизмов критично для:

  • Разработчиков, создающих свои ОС на базе AOSP.

  • Понимания жизненного цикла приложений на глубоком уровне.

  • Корректной реализации сохранения/восстановления состояния (Bundle, ViewModel с SavedStateHandle).

Я разберу ключевые системные компоненты (Zygote, SystemServer, AMS, Binder) и процесс восстановления состояния через Bundle.

Привет, Хабр! Я Михаил Богатиков, Android‑разработчик в ПСБ.
На одном из собеседований мне задали вопрос, про восстановление приложения после смерти, на который я не смог ответить. Мне стало интересно и я решил изучить этот вопрос и в результате появилась эта статья.

Но собрать информацию оказалось не так‑то и просто. И после долгих поисков, запросов к нейросеткам (которые ещё и привирали порой), просмотра документации и анализа всей полученной информации, я получил базовое представление о теме.

Решил сократить и при этом структурировать всё, что нашёл, и поделиться с сообществом — возможно, кому‑то это поможет подготовиться к собеседованию на сеньора и не потерять при этом кучу времени и нервов:)

Запуск Android‑системы

Базовый процесс инициализации ОС. Понимание необходимо для диагностики стартовых проблем и глубокой работы с AOSP.

Точная последовательность инициализации компонентов

ServiceManager → Zygote → SystemServer → (AMS + PMS) → SystemUI → Launcher
Процесс загрузки — основа для работы приложений:

  1. Инициализация ServiceManager:

    • Первый системный сервис с фиксированным Binder‑токеном 0.

    • Служит глобальным реестром для всех Binder‑сервисов системы.

    • Работает как системный демон.

  2. Запуск Zygote (фабрики процессов):

    • Главный «родительский» процесс, оптимизированный для быстрого порождения дочерних процессов приложений через fork().

    • Запускается вторым, предзагружает core‑библиотеки (ART, core JAR), обрабатывает команды через сокет.

  3. Создание SystemServer:

    • Этот ключевой процесс создаётся Zygote.

    • SystemServer запускает и управляет основными системными сервисами.

    • Создаёт и регистрирует:

      • ActivityManagerService (AMS)

      • PackageManagerService (PMS)

    • Отправляет Broadcast с ACTION_SYSTEM_READY.

    • Запускает отдельный процесс для SystemUI.

  4. Регистрация критических сервисов:

    • SystemServer создает и регистрирует в ServiceManager:

      • ActivityManagerService (AMS) — управляет жизненным циклом приложений.

      • PackageManagerService (PMS) — управляет установленными приложениями.

  5. Запуск SystemUI:

    SystemServer создает отдельный процесс для SystemUI (строка состояния, навигация).

  6. Запуск Launcher:

    • SystemServer через AMS (systemReady()) инициирует запуск домашнего экрана.

    • AMS отправляет Intent с ACTION_MAIN и CATEGORY_HOME.

  7. Работа Launcher:

    • Создается экземпляр Launcher (обычно Activity).

    • Запрос к PMS за списком всех установленных приложений.

    • Построение интерфейса (иконки, метаданные).

    ServiceManager: системный телефонный справочник

    Центральный реестр Binder‑сервисов. Ключ к пониманию IPC и взаимодействия системных компонентов.

    • Назначение: Централизованный реестр всех Binder‑сервисов.

    • Принцип работы:

      • Каждому Binder‑сервису присваивается уникальный 32-битный токен.

      • ServiceManager хранит таблицу: Имя сервиса → Binder токен.

      • Клиент запрашивает токен по имени → получает токен → взаимодействует напрямую с сервисом по этому токену.

    • Ключевые особенности:

      • Имеет фиксированный токен 0 (единственный в системе).

      • Один из первых запускаемых сервисов.

      • Точка входа для клиентов для поиска сервисов.

      • Безопасность обеспечивается Binder‑драйвером (проверка PID/UID клиента).

    SystemServer: мозг и мышцы пользовательского пространства

    Главный процесс, запускающий критические сервисы (AMS, PMS). Основа работы всей пользовательской части Android.

    • Роль: Главный системный процесс, запускающий и координирующий работу ключевых служб ОС.

    • Запуск: Инициируется Zygote после загрузки ядра.

    • Основные функции:

      • Управление жизненным циклом системных сервисов.

      • Обеспечение работы UI, координация приложений, управление ресурсами.

    • Управляемые сервисы (примеры):

      • ActivityManagerService (AMS)

      • PackageManagerService (PMS)

      • WindowManagerService (WMS)

      • PowerManagerService

      • ConnectivityService

      • LocationManagerService

      • NotificationManagerService

      • AudioService

    • Особенности:

      • Сервисы работают как потоки внутри процесса SystemServer.

      • Высокий приоритет, автоматический перезапуск упавших служб.

      • Обеспечивает «песочницы» (sandbox) для безопасности.

    Механизм Binder: кровеносная система IPC

    Базовый механизм IPC в Android. Обязателен для понимания передачи данных (включая Bundle) между процессами.

    • Назначение: Высокоуровневый, безопасный механизм Межпроцессного Взаимодействия (IPC) в Android.

    • Ключевые Компоненты:

      • Binder‑драйвер: Ядро Linux, обеспечивающее безопасную передачу.

      • Parcel: Контейнер для данных (примитивы, Parcelable, Bundle), оптимизированный для сериализации/десериализации при передаче через Binder.

      • Binder‑токены: Уникальные идентификаторы процессов/сервисов (выдаются ServiceManager).

    • Как это работает для Bundle:

      • Данные состояния помещаются в Bundle.

      • Bundle сериализуется в Parcel.

      • Parcel передается через Binder IPC (например, от приложения к AMS или обратно).

      • Получатель десериализует Parcel обратно в Bundle.

    • Жизненный цикл Binder‑соединения «умирает» при:

      • Корректном завершении процесса приложения (back press, finish).

      • Перезагрузке устройства.

      • Сильной нехватке памяти (Low Memory Killer).

      • Восстановление: Система (через AMS) воссоздает соединения при перезапуске процесса на основе сохраненных записей.

    ActivityManagerService (AMS): диспетчер процессов

    Ядро управления жизненным циклом приложений. Знание AMS критично для работы с активностями, процессами и восстановлением состояния.

    • Роль: Центральный сервис, управляющий жизненным циклом приложений, активностей, задач и процессов.

    • Основные функции AMS:

      • Управление компонентами: Запуск/остановка Activity, Services, BroadcastReceivers; управление стеками задач (TaskRecord).

      • Управление процессами: Создание процессов (через Zygote), уничтожение (по приоритету), отслеживание состояния (ProcessRecord).

      • Сохранение и Восстановление Состояния: Координация вызова onSaveInstanceState(), хранение полученных Bundle (в ActivityRecord), передача их обратно при воссоздании Activity.

      • Безопасность и Разрешения: Проверка прав доступа компонентов.

      • Управление памятью: Мониторинг использования, реагирование на нехватку (уничтожение фоновых процессов).

      • Обработка Intent: Маршрутизация интентов (особенно стартовых для приложений, хранит последний использованный для запуска).

    • Взаимодействие: Осуществляется через Binder IPC. Приложение (ActivityThread) связывается с AMS для выполнения операций (запуск Activity, сохранение состояния и т. д.).

    Структуры данных и управление состоянием

    • Иерархия компонентов:

      • ProcessRecord (PID, имя, приоритет)

      • TaskRecord (группа Activity)

      • ActivityRecord (состояние, Bundle данных)

    • Хранение Intent:

      • Сохраняется только стартовый Intent приложения

      • Последующие Intent не сохраняются после убийства процесса

      Создание процесса приложения: от запроса до UIПолный цикл запуска приложения. Помогает отлаживать старт приложения и понимать роль Zygote/ActivityThread.

Что происходит, когда пользователь тапает на иконку в Launcher:

  1. Запрос от Launcher: Launcher отправляет Intent (с ACTION_MAIN, CATEGORY_LAUNCHER) в AMS.

  2. Проверка AMS: AMS запрашивает у PMS информацию о приложении (манифест, точка входа — Activity с фильтром CATEGORY_LAUNCHER).

  3. Проверка Процесса:

    • Если процесс приложения уже существует: AMS находит его запись (ProcessRecord), выводит его root Activity на передний план (Resume) и передает сохраненный Bundle(если есть) в onCreate()/onRestoreInstanceState().

    • Если процесса нет:

      1. Fork от Zygote: AMS отправляет запрос Zygote через сокет на создание нового процесса (fork()).

      2. Инициализация процесса: В новом процессе запускается ZygoteInit.main(), инициализирующая среду выполнения (ART/Dalvik).

      3. Создание главного потока: Создается main (UI) thread.

      4. Запуск ActivityThread: Вызывается main() метод ActivityThread — «сердце» приложения.

      5. Привязка к AMS: ActivityThread.attach() связывает процесс приложения с AMS через Binder, регистрируя новый ApplicationThread (Binder‑интерфейс приложения для AMS).

      6. Инициализация Looper/Handler: Создаются Looper (обработка очереди сообщений) и Handler (обработка сообщений, вызов методов жизненного цикла) для главного потока.

      7. Создание Application: AMS инициирует создание объекта Application (вызов onCreate()).

      8. Создание Launch Activity:

        • ActivityTaskManager (часть AMS) получает команду создать Activity.

        • ActivityStarter обрабатывает запрос.

        • AMS отправляет транзакцию приложению (через ApplicationThread) на создание Activity.

      9. Обработка в ActivityThread: Полученная транзакция (ClientTransaction) обрабатывается. Через Instrumentation создается экземпляр Activity.

      10. Жизненный цикл Activity: Вызываются onCreate() → onStart() → onResume()(передача сохраненного Bundle в onCreate() при восстановлении). UI отображается пользователю.

Жизненный цикл процесса: приоритеты и выживание
Система приоритетов процессов и политики уничтожения. Позволяет оптимизировать приложение для работы в фоне.

Приоритеты и политики уничтожения

Система ранжирует процессы по важности и убивает их при нехватке памяти, начиная с наименее важных:

  1. Foreground Process (Процесс переднего плана): Наивысший приоритет. Уничтожается в крайнем случае.
    Признаки: Активность в onResume(), BroadcastReceiver в onReceive(), Service в onStart()/onCreate()/onDestroy().

  2. Visible Process (Видимый процесс): очень высокий приоритет. Уничтожается, только если нужно освободить ресурсы для Foreground процессов.
    Признаки: Активность видима, но не на переднем плане (onPause(), например, под диалогом), Service с startForeground() (с нотификацией), системные сервисы (живые обои, IME).

  3. Service Process (Процесс службы): средний приоритет. Запущен Service через startService(). Уничтожается, если памяти не хватает для работы более приоритетных процессов.
    Важно: Длительные задачи (>30 мин) могут привести к понижению приоритета. Используйте WorkManager!

  4. Cached Process (Кэшированный процесс): низший приоритет. Уничтожается первым при нехватке памяти. Содержит завершенные (onStop()) активности. Их уничтожение не влияет на пользователя при возврате (если состояние сохранено в Bundle/ViewModel).
    Важно знать про Android 13+: Кэшированные процессы могут сильно ограничиваться в ресурсах ЦП. Политика упорядочивания списка кэша зависит от OEM (обычно сохраняются «полезные» процессы — Launcher, последние активности).

Важно: Приоритет процесса может повышаться, если он связан (bound) с более приоритетным процессом (например, через Context.BIND_AUTO_CREATE или ContentProvider).

Восстановление приложения: магия Bundle

Взаимодействие системных сервисов (сервер) и кода приложения (клиент). Ключ к пониманию вызовов жизненного цикла.

Это ключевой механизм выживания состояния при внезапной смерти процесса (нехватка памяти, поворот экрана).

Этапы сохранения

  1. Системный вызов: При угрозе уничтожения активности (но не процесса!) система вызывает ее onSaveInstanceState(outState: Bundle).

  2. Сохранение разработчиком: Разработчик помещает в outState простые данные (строки, числа, Parcelable), необходимые для восстановления UI (id элементов, позиция прокрутки, флаги). Система автоматически сохраняет состояние View с ID.

  3. Сохранение ViewModel: Если используется ViewModel с SavedStateHandle, данные в SavedStateHandle также автоматически сохраняются в Bundle.

  4. Передача в AMS: Система сериализует Bundle в Parcel и передает через Binder IPC в AMS. AMS хранит его в ActivityRecord.


Этапы восстановления после убийства процесса

  1. Инициация AMS: Пользователь возвращается к убитому приложению.

  2. Создание Процесса: AMS создает новый процесс через Zygote (см. раздел 6).

  3. Создание ActivityThread: В новом процессе запускается ActivityThread.

  4. Привязка к AMS: ActivityThread привязывается к AMS, регистрируя ApplicationThread.

  5. Воссоздание Application: AMS инициирует создание объекта Application (onCreate()).

  6. Воссоздание Activity: AMS отправляет команду на создание Activity, включая сохраненный Bundle.

  7. Обработка в ActivityThread: Транзакция обрабатывается. Создается экземпляр Activity.

  8. Передача Bundle: При вызове onCreate(savedInstanceState: Bundle?) в новую Activity передается тот самый Bundle, сохраненный ранее в AMS.

  9. Восстановление разработчиком: Разработчик извлекает данные из savedInstanceState и восстанавливает состояние UI/логики. Данные из SavedStateHandle в ViewModelвосстанавливаются автоматически.

Критические замечания и рекомендации

  • Ограничение размера Bundle: Общий размер Bundle для всего процесса ограничен Binder IPC (обычно ~1 МБ). Не стоит передавать слишком большие сущности, а также постарайтесь ограничиться id для поиска сущности и базовыми полями

  • Когда Bundle == null: savedInstanceState будет null, если:

    • Активность создается впервые.

    • Процесс был убит намеренно пользователем (через «Недавние») или системой при перезагрузке устройства.

    • Возникла ошибка при сериализации/десериализации Parcel.

  • Parcelable vs Serializable: Всегда предпочитайте Parcelable. Он создан специально для Android, быстрее и эффективнее Serializable (который использует reflection).

  • ViewModel + SavedStateHandle: Оптимальный способ сохранять данные, связанные с UI, переживающие конфигурационные изменения и легкое убийство процесса. Поддерживает LiveData, StateFlow, Compose State.

  • Расширенные сценарии (SavedStateRegistry): Для кастомной логики сохранения несложных данных (не Parcelable/Serializable) используйте SavedStateRegistry и SavedStateProvider (доступно с Lifecycle 2.3.0-alpha03). Пример: Сохранение пути к временному файлу в Bundle, а самого файла — в хранилище.

  • Для сложных/больших данных: Используйте постоянные хранилища:

    • SharedPreferences (небольшие наборы «ключ‑значение»).

    • Room (база данных SQLite).

    • Файловая система (для больших бинарных данных, кэша).

    • DataStore (современная замена SharedPreferences).

Заключение

Понимание работы Zygote, SystemServer, AMS и Binder IPC — ключ к глубокому владению платформой Android. Механизм сохранения состояния через Bundle, координируемый AMS и реализуемый через Binder и Parcel, является фундаментальным для обеспечения устойчивости приложений к пересозданию процессов. Используйте ViewModel с SavedStateHandle для простых UI‑данных, Parcelable для эффективной сериализации и постоянные хранилища для критически важной информации, соблюдая ограничения Bundle. Это гарантирует плавную работу приложения в любых условиях.

Комментарии (0)