Repository navigation
Android: реализовать опциональный автозапуск прокси после загрузки системы #96
Description
Контекст
Техническая задача на основе пользовательского запроса #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 должен:
- Проверить, включён ли автозапуск.
- Если выключен — завершиться без запуска сервиса.
- Если включён — проверить, что последняя сохранённая конфигурация достаточна для запуска выбранного frontend.
- Запустить существующий
ProxyServiceчерез штатныйACTION_START. - Для актуальных версий 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
Проверить:
- Включить автозапуск.
- Запустить прокси и убедиться, что рабочая конфигурация сохранена.
- Перезагрузить устройство/эмулятор.
- Не открывая приложение вручную, дождаться завершения boot.
- Убедиться, что
ProxyServiceзапущен и локальный proxy port доступен. - Открыть приложение и убедиться, что UI показывает запущенное состояние.
- Выключить автозапуск.
- Повторить 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.
Связано
- Пользовательский запрос: Отсутствует автозапуск с системой #95
- Milestone: версия 5
Activity
Android: add optional proxy autostart after boot (#97)