Skip to content

Android: реализовать опциональный автозапуск прокси после загрузки системы #96

Closed

Description

@Regstar2

Контекст

Техническая задача на основе пользовательского запроса #95. Исходный issue #95 не изменять и не закрывать в рамках этой задачи.

Сейчас приложение умеет запускать ProxyService вручную из UI и сохраняет последнюю рабочую конфигурацию прокси в ProxyPrefs, но в AndroidManifest.xml нет разрешения RECEIVE_BOOT_COMPLETED и отдельного BroadcastReceiver для восстановления прокси после перезагрузки устройства.

Нужно вернуть опциональный автозапуск, аналогичный по назначению возможности из исходного Android-клиента, но реализовать его поверх текущей архитектуры приложения и существующего foreground ProxyService.

Цель

Добавить пользовательскую настройку «Автозапуск при включении устройства», при которой после завершения загрузки Android приложение автоматически восстанавливает локальный прокси с последней сохранённой конфигурацией без необходимости вручную открывать приложение.

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

Требования

1. Настройка автозапуска

  • Добавить постоянную boolean-настройку, например autostart_on_boot.
  • Значение по умолчанию: выключено.
  • Настройка должна сохраняться в существующем хранилище настроек приложения либо в отдельном небольшом repository/store, совместимом с текущей архитектурой.
  • Изменение настройки должно применяться сразу и не требовать перезапуска приложения.

2. UI

Добавить переключатель автозапуска в подходящий раздел настроек приложения, предпочтительно в раздел настроек приложения/службы.

Текст должен однозначно объяснять поведение:

  • заголовок: «Автозапуск при включении устройства»;
  • пояснение: прокси будет автоматически запускаться после загрузки Android с последней сохранённой конфигурацией.

Переключатель не должен выглядеть как обязательная настройка и не должен включаться автоматически после обновления.

3. Android boot receiver

Добавить в manifest:

  • android.permission.RECEIVE_BOOT_COMPLETED;
  • внутренний BroadcastReceiver с android:exported="false";
  • intent-filter для android.intent.action.BOOT_COMPLETED.

Receiver должен:

  1. Проверить, включён ли автозапуск.
  2. Если выключен — завершиться без запуска сервиса.
  3. Если включён — проверить, что последняя сохранённая конфигурация достаточна для запуска выбранного frontend.
  4. Запустить существующий ProxyService через штатный ACTION_START.
  5. Для актуальных версий Android использовать корректный путь запуска foreground service и не обходить системные ограничения Android.

Не запускать Activity и не открывать UI после загрузки системы.

4. Использование существующей конфигурации

Не дублировать конфигурацию прокси в receiver.

Автозапуск должен использовать тот же источник данных, который уже использует ProxyService.loadLastConfig():

  • последний локальный порт;
  • runtime config / IPs;
  • pool size;
  • выбранный local proxy frontend;
  • связанные настройки маршрутизации, Cloudflare, Worker, AWG/WARP и другие существующие настройки, которые сервис читает при обычном старте.

Receiver должен инициировать обычный путь запуска сервиса, а не создавать отдельный boot-specific runtime.

5. Валидность конфигурации

Автозапуск не должен приводить к циклическим ошибкам или бессмысленному foreground service.

Минимальные правила:

  • для SOCKS5/frontend, где требуется непустая runtime-конфигурация, сохранить текущее поведение ProxyService: при невалидной конфигурации сервис не должен оставаться запущенным;
  • для frontend, который может стартовать без last_runtime_ips, не вводить искусственное ограничение;
  • ошибки запуска должны корректно завершать сервис и оставлять приложение в консистентном состоянии.

6. Foreground service

Существующий ProxyService уже является foreground service с типом specialUse.

При запуске из boot receiver:

  • использовать существующий ProxyService.ACTION_START;
  • сервис должен перейти в foreground в допустимый системой срок;
  • не создавать второй сервис или отдельную boot-службу;
  • не создавать отдельный notification channel;
  • использовать текущую notification infrastructure ProxyService.

7. Состояние после ручной остановки

Нужно разделить две вещи:

  • включённая настройка «Автозапуск при включении устройства»;
  • текущее состояние сервиса.

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

При этом выключенный автозапуск никогда не должен запускать сервис после reboot.

8. Логирование

Добавить privacy-safe события в существующую систему логирования:

  • получен BOOT_COMPLETED;
  • автозапуск выключен — запуск пропущен;
  • автозапуск разрешён — отправлен ACTION_START;
  • запуск пропущен из-за невалидного сохранённого состояния;
  • ошибка запуска receiver/service.

Не логировать секреты, домены без маскирования, токены, WARP/AWG ключи или содержимое приватной конфигурации.

9. Совместимость

Проверить как минимум:

  • холодную загрузку устройства;
  • перезагрузку;
  • запуск после обновления приложения не должен сам по себе включать автозапуск;
  • автозапуск выключен;
  • автозапуск включён + валидная конфигурация;
  • автозапуск включён + невалидная/неполная конфигурация;
  • повторная доставка broadcast не должна создавать два экземпляра proxy runtime;
  • приложение после автоматического старта должно корректно отображать состояние уже запущенного ProxyService.

Если OEM прошивка дополнительно блокирует автозапуск приложений, не пытаться обходить системные/OEM ограничения скрытыми механизмами.

Предлагаемая реализация

Новый компонент

Например:

BootCompletedReceiver.kt

Ответственность receiver должна быть минимальной:

  • прочитать только флаг автозапуска;
  • выполнить базовую проверку возможности старта;
  • сформировать intent к ProxyService;
  • вызвать foreground service start;
  • завершиться.

Не переносить сетевую или routing-логику в receiver.

Хранилище настройки

Предпочтительно выделить небольшой typed store, например:

AutostartPreferences

или использовать уже существующий подход проекта к небольшим настройкам.

Пример API:

object AutostartPreferences {
    fun isEnabled(context: Context): Boolean
    fun setEnabled(context: Context, enabled: Boolean)
}

Конкретное имя не принципиально; важно не разносить строковые ключи по UI, receiver и service.

Manifest

Ожидаемые изменения:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

и зарегистрированный receiver для BOOT_COMPLETED.

Не добавлять лишние permissions.

Тесты

Unit tests

Покрыть как минимум:

  • default = false;
  • сохранение/чтение флага;
  • решение receiver: disabled → skip;
  • enabled + valid config → start;
  • enabled + invalid config → skip;
  • повторный вызов не создаёт отдельную альтернативную конфигурацию.

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

Android / instrumentation smoke

Проверить:

  1. Включить автозапуск.
  2. Запустить прокси и убедиться, что рабочая конфигурация сохранена.
  3. Перезагрузить устройство/эмулятор.
  4. Не открывая приложение вручную, дождаться завершения boot.
  5. Убедиться, что ProxyService запущен и локальный proxy port доступен.
  6. Открыть приложение и убедиться, что UI показывает запущенное состояние.
  7. Выключить автозапуск.
  8. Повторить reboot и убедиться, что сервис не стартует.

Для эмулятора можно дополнительно проверить обработку broadcast через ADB, но финальная проверка должна включать реальную последовательность reboot → BOOT_COMPLETED.

Acceptance criteria

  • В настройках есть выключенный по умолчанию переключатель автозапуска.
  • Значение настройки сохраняется между запусками приложения.
  • В manifest добавлен только необходимый permission RECEIVE_BOOT_COMPLETED и boot receiver.
  • При отключённом автозапуске после reboot сервис не запускается.
  • При включённом автозапуске после reboot стартует существующий ProxyService.
  • Используется последняя сохранённая конфигурация, без отдельного boot-config.
  • Не запускается Activity и не требуется вручную открывать приложение.
  • Foreground notification создаётся существующим механизмом ProxyService.
  • Невалидная сохранённая конфигурация обрабатывается без crash/restart loop.
  • Повторный broadcast не создаёт дублирующий proxy runtime.
  • UI после автоматического запуска корректно отражает состояние сервиса.
  • Добавлены privacy-safe boot/autostart logs.
  • Добавлены unit tests и Android smoke-проверка.
  • Существующий ручной Start/Stop/Reconnect/Reconfigure не регрессировал.
  • Исходный issue Отсутствует автозапуск с системой #95 не изменён.

Не входит в задачу

  • обход OEM-ограничений автозапуска Xiaomi/Huawei/Samsung и подобных прошивок;
  • скрытый запуск приложения через Activity;
  • создание нового background/foreground service вместо ProxyService;
  • изменение routing-алгоритмов;
  • изменение конфигурации Cloudflare/Worker/AWG/WARP;
  • автоматическое включение опции существующим пользователям;
  • закрытие или редактирование Отсутствует автозапуск с системой #95.

Связано

Activity

  1. added this to the v1.11.1 milestone on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions