MidТеория11 min

Android архитектура

Android stack, ART runtime, процессы, IPC, lifecycle компонентов и их влияние на System Design мобильных систем

Зачем backend-инженеру знать Android

При проектировании систем важно понимать клиентскую сторону. Android -- самая распространённая мобильная ОС (72%+ рынка). Знание её архитектуры помогает:

  • Проектировать API, учитывающие ограничения мобильных клиентов
  • Понимать, почему мобильные клиенты ведут себя иначе (батарея, сеть, lifecycle)
  • Принимать решения об offline-first архитектуре
  • Оптимизировать протоколы для мобильных сетей

Android Software Stack

Android построен на ядре Linux с несколькими дополнительными уровнями.

┌─────────────────────────────────┐
│       System Apps               │  Телефон, Контакты, Камера
├─────────────────────────────────┤
│       Application Framework     │  Activity Manager, Content Providers
├─────────────────────────────────┤
│  Android Runtime │ Native Libs  │  ART, libc, OpenGL, SQLite
├─────────────────────────────────┤
│  Hardware Abstraction Layer     │  Camera HAL, Audio HAL
├─────────────────────────────────┤
│       Linux Kernel              │  Drivers, Binder, Power Mgmt
└─────────────────────────────────┘

Уровни стека

Уровень Компоненты Аналогия в backend
Applications Пользовательские приложения Клиентские приложения
Framework Activity, Service, ContentProvider Application framework (Symfony)
Runtime ART (Android Runtime) PHP Runtime / Go Runtime
Native Libraries libc, SQLite, OpenSSL Системные библиотеки
HAL Абстракция аппаратуры Device drivers
Kernel Linux kernel ОС сервера

ART (Android Runtime)

От Dalvik к ART

Android использовал JIT-компиляцию (Dalvik VM), а затем перешёл на AOT + JIT (ART).

Параметр Dalvik (старый) ART (современный)
Компиляция JIT (Just-In-Time) AOT + JIT (гибрид)
Установка приложения Быстрая Медленнее (компиляция)
Запуск приложения Медленнее Быстрее
RAM Больше (JIT кэш) Оптимизирован
Garbage Collection Stop-the-world Concurrent, generational

Garbage Collection в ART

ART использует generational GC, разделяющий объекты на поколения:

  • Young generation: короткоживущие объекты (часто собираются)
  • Old generation: долгоживущие объекты (редко собираются)
  • Large Object Space: большие объекты (отдельный пул)

Аналогия с PHP: PHP использует reference counting + cycle collector. В PHP каждый запрос -- это "поколение": в конце запроса вся память освобождается. Это проще, чем generational GC, но не подходит для долгоживущих процессов.

Процессы в Android

Модель процессов

Каждое Android-приложение работает в отдельном процессе Linux с собственным UID. Это обеспечивает изоляцию -- одно приложение не может читать память другого.

App A (UID 10001) ──── Process A (Dalvik/ART VM)
App B (UID 10002) ──── Process B (Dalvik/ART VM)
App C (UID 10003) ──── Process C (Dalvik/ART VM)
                         │
                    Linux Kernel (общее ядро)

Приоритеты процессов

Android агрессивно управляет процессами для экономии батареи и памяти:

Приоритет Описание Когда убивается
Foreground Активно используется Последний (только при критическом OOM)
Visible Виден, но не в фокусе При нехватке памяти
Service Фоновый сервис При значительной нехватке
Background В фоне, не активен Первый кандидат
Empty Нет активных компонентов Первый убивается

Для System Design: Мобильное приложение может быть убито ОС в любой момент. API должен быть idempotent, поддерживать retry, и данные должны синхронизироваться корректно после восстановления.

IPC (Inter-Process Communication)

Binder

Binder -- это основной механизм IPC в Android. Это высокопроизводительный RPC-механизм, реализованный как драйвер ядра.

App Process          System Server
    │                     │
    ├── Binder Proxy  ──► Binder Stub ──► Service
    │   (клиент)          (сервер)
    │                     │
    └────── Binder Driver (kernel) ──────┘

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

  • Один копирование данных (вместо двух в обычных pipe/socket)
  • Встроенная аутентификация (UID/PID вызывающего)
  • Поддержка передачи файловых дескрипторов
  • Синхронные вызовы (блокирующие)

Другие механизмы IPC

Механизм Использование Аналогия в backend
Binder Вызовы системных сервисов gRPC/REST API
Intent Запуск Activity/Service Message Queue
ContentProvider Доступ к данным между приложениями REST API для данных
Broadcast Широковещательные уведомления Pub/Sub (Redis, RabbitMQ)
Shared Memory (Ashmem) Быстрый обмен большими данными Shared Memory / mmap

Activity Lifecycle

Жизненный цикл Activity

onCreate() → onStart() → onResume() → [Активна]
                                          │
                                    onPause() → onStop() → onDestroy()
                                       │            │
                                       │      onRestart() → onStart()
                                       │
                                 [Частично видна]

Влияние на проектирование API

Жизненный цикл Android создаёт специфические требования к backend:

<?php

declare(strict_types=1);

/**
 * API design considerations for mobile clients.
 * Mobile apps can be killed and restarted at any moment.
 */
final class MobileAwareApiController
{
    public function __construct(
        private readonly SyncService $syncService,
        private readonly IdempotencyService $idempotency,
    ) {}

    /**
     * Idempotent endpoint for mobile clients.
     * Mobile app may retry requests if it was killed mid-request.
     *
     * @param string $idempotencyKey Client-generated unique key
     * @param array<string, mixed> $payload
     * @return array{status: string, data: mixed}
     */
    public function createOrder(
        string $idempotencyKey,
        array $payload,
    ): array {
        // Check if this request was already processed
        $existing = $this->idempotency->find($idempotencyKey);
        if ($existing !== null) {
            // Return same response without re-processing
            return ['status' => 'ok', 'data' => $existing];
        }

        // Process the order
        $order = $this->processOrder($payload);

        // Store result with idempotency key
        $this->idempotency->store($idempotencyKey, $order, ttlSeconds: 86400);

        return ['status' => 'created', 'data' => $order];
    }

    /**
     * Delta sync endpoint for mobile clients.
     * Instead of fetching all data, client sends last sync timestamp.
     * Returns only changes since that timestamp.
     */
    public function syncData(
        string $userId,
        string $lastSyncAt,
    ): array {
        $changes = $this->syncService->getChangesSince(
            userId: $userId,
            since: new \DateTimeImmutable($lastSyncAt),
        );

        return [
            'created' => $changes['created'],
            'updated' => $changes['updated'],
            'deleted' => $changes['deleted_ids'],
            'sync_timestamp' => (new \DateTimeImmutable())->format('c'),
        ];
    }
}
## Ограничения мобильных клиентов

Батарея

Android ограничивает фоновую активность для экономии батареи:

  • Doze Mode: ограничивает сеть, sync, alarms в режиме простоя
  • App Standby: приложения в фоне получают меньше ресурсов
  • Background Execution Limits: ограничения на фоновые сервисы

Сеть

Мобильная сеть принципиально отличается от проводной:

Параметр Wi-Fi 4G LTE 3G
Латентность 1-10 мс 30-100 мс 100-500 мс
Пропускная способность 100+ Мбит/с 10-100 Мбит/с 1-5 Мбит/с
Стабильность Высокая Средняя Низкая
Энергопотребление Низкое Высокое Очень высокое

Рекомендации для API

  1. Batch API: объединять несколько запросов в один
  2. Compression: gzip/brotli для уменьшения трафика
  3. Pagination: не отдавать все данные разом
  4. Delta sync: отдавать только изменения
  5. Offline-first: клиент работает без сети, синхронизация при подключении
  6. Idempotent APIs: безопасные повторные запросы
<?php

declare(strict_types=1);

/**
 * Batch API endpoint to reduce number of network requests.
 * Mobile clients benefit from fewer, larger requests.
 */
final class BatchApiController
{
    /**
     * Process multiple API calls in a single HTTP request.
     * Reduces latency overhead from multiple round-trips.
     *
     * @param array<int, array{method: string, path: string, body?: array}> $requests
     * @return array<int, array{status: int, body: mixed}>
     */
    public function batch(array $requests): array
    {
        if (count($requests) > 20) {
            throw new \InvalidArgumentException('Maximum 20 requests per batch');
        }

        $responses = [];

        foreach ($requests as $index => $request) {
            $responses[$index] = $this->processSubRequest(
                method: $request['method'],
                path: $request['path'],
                body: $request['body'] ?? [],
            );
        }

        return $responses;
    }

    /**
     * @return array{status: int, body: mixed}
     */
    private function processSubRequest(
        string $method,
        string $path,
        array $body,
    ): array {
        // Route sub-request to appropriate handler
        // Each sub-request runs independently
        try {
            $result = $this->router->dispatch($method, $path, $body);
            return ['status' => 200, 'body' => $result];
        } catch (\Throwable $e) {
            return ['status' => 500, 'body' => ['error' => $e->getMessage()]];
        }
    }
}
## Push-уведомления (FCM)

Firebase Cloud Messaging (FCM) -- стандартный механизм push-уведомлений для Android.

Backend → FCM Server → Google Play Services → Приложение

Особенности:
- Размер payload: до 4 КБ
- Гарантия доставки: at-least-once (может дублироваться)
- Батарея: эффективнее polling, использует общий канал
- Rate limits: зависят от приоритета сообщения

Для System Design: Push-уведомления -- это не надёжный канал доставки. Они могут не дойти (Doze mode, нет сети) или дублироваться. Для критичных данных используйте pull-based синхронизацию в дополнение к push.

Выводы

  • Android построен на Linux, но с существенными модификациями (Binder, ART, HAL)
  • Каждое приложение изолировано в своём процессе и UID
  • ОС может убить приложение в любой момент -- API должен быть idempotent
  • Мобильная сеть нестабильна -- нужны retry, delta sync, batch API
  • Push-уведомления -- at-least-once, не гарантируют доставку
  • Понимание клиентских ограничений помогает проектировать правильные API