← На главную

Опубликовано

Sber TV: ADB, деблоат и VPN на телевизоре без Play Market

Автор: Гусев Николай [портфолио]

Темы: ai-agents, android, on-device, privacy

Вечером телевизор начал вести себя так, как обычно ведет себя Android, которому давно пора заглянуть в память. После сна интерфейс становился вязким, VK отвечал "история не грузится", а перезагрузка возвращала нормальную жизнь ровно до следующего дня. Жена смотрела на это без инженерного интереса. Ей нужен был телевизор, а не мой будущий отчёт по причине сбоя.

Я Николай, инженер, поэтому сначала пытался не трогать работающую коробку. Потом понял, что это уже не коробка. Это Android TV, который можно диагностировать. Внутри Sber SBX с SaluteTV, чип Amlogic, 2 ГБ RAM и Android 13 без GMS. Система называется StarOS 1.103.90-b32217, но под слоем брендинга остаётся AOSP. Значит, есть обычный путь: включить отладку, подключиться по ADB, посмотреть процессы и перестать гадать.

Отдельная особенность этой модели важнее названия прошивки. Архитектура только armeabi-v7a, то есть 32-bit. APK для x86 или arm64 сюда не ставятся. Это выясняется быстро, но лучше узнать до того, как начнёшь искать проблему в установщике.

Сначала я открыл ADB

Официальный маршрут через developers.sber.ru/studio в моём случае был пустым. Рабочий оказался знакомым по любому Android: "Настройки", затем "Об устройстве", 7 нажатий по "Номер сборки", меню разработчика, "Отладка по Wi-Fi" и включение переключателя.

Тут телевизор подложил первую граблю. Диалог выводит код и порт, у меня это был 34893. Выглядит убедительно, но использовать его для постоянного подключения не надо. Это транзитный одноразовый порт для первичного handshake. Основной ADB-порт у телевизора 5555.

Я подключался к ТВ в домашней сети и подтвердил на экране телевизора запрос "Разрешить отладку?":

`adb connect <IP>:5555`

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

`adb devices                       # должно быть "device", не "unauthorized"
adb shell getprop ro.build.version.release   # 13
adb shell cat /proc/meminfo | head -3
adb shell top -n 1 -b | head -25`

Есть неприятная мелочь для будущих сеансов. После каждого reboot порт 5555 закрывается. Отладку по Wi-Fi приходится включать снова. Это не поломка ADB и не повод перебирать порты Салюта. Именно настройка на телевизоре возвращает доступ.

Неприятная правда оказалась в памяти

Первые команды подтвердили ощущение от дивана. После пробуждения в swap уже ушло около 500 МБ из 1 ГБ, а MemFree держался около 140 МБ. Когда телевизор выходит из сна, системе приходится откачивать данные из swap. На 2 ГБ RAM это заметно не в бенчмарке, а в моменте, когда приложение не может быстро открыть историю.

top добавил конкретного виновника в картину. Процесс com.vk.tv занимал 231 МБ RAM, потреблял 38% CPU и накопил 19 CPU-часов в фоне. Я не делаю из этого вывод, что приложение единолично сломало телевизор. Но сочетание фонового процесса, заполненного swap и почти пустой свободной памяти объясняет симптом лучше, чем мистические разговоры о "тяжёлой прошивке".

Я снял состояние через dumpsys meminfo, подчистил кэш и остановил процесс:

`pm trim-caches 9999999M
am force-stop com.vk.tv
dumpsys meminfo <pkg>`

Для com.vk.tv я также выполнил компиляцию с профилем скорости, чтобы код прогрелся под реальный сценарий запуска:

`cmd package compile --check-prof false -m speed-profile com.vk.tv`

Это дало телевизору передышку. Важно назвать вещь своим именем: лечение паллиативное. После сна набор процессов и память снова могут прийти к тому же состоянию. Зато ADB превратил семейную жалобу "всё тормозит" в наблюдаемую причину и понятный порядок действий.

Почему VPN я настраивал выборочно

Параллельно хотелось решить другую задачу. SmartTube должен ходить через мой внешний сервер, а остальной трафик телевизора должен оставаться обычным. Завернуть в туннель всё устройство можно, но это неудобно для приложений, которые не нуждаются в VPN. Мне нужен был split tunneling, где правило задано не на глаз, а проверено средствами системы.

Для этой платформы подошёл v2rayNG. Я взял v2rayNG 2.2.6 armv7. Здесь снова работает правило архитектуры: нужен вариант для armeabi-v7a. Имя пакета тоже стоит сверить до первой команды. Верное имя com.v2ray.ang, а не похожее com.v2ray.ng.

Установка через ADB выглядит обычно:

`adb install v2rayNG_armv7.apk`

Но на этом телевизоре простая установка ещё не означает работающий туннель. Его не поднимают три разрешения, если пропустить хотя бы одно. Именно этот участок я бы проверил первым, если v2rayNG установлен, профиль импортирован, а соединения нет:

`appops set com.v2ray.ang ACTIVATE_VPN allow
cmd appops set com.v2ray.ang ACTIVATE_PLATFORM_VPN allow
dumpsys deviceidle whitelist +com.v2ray.ang`

Первое разрешает активацию VPN, второе разрешает платформенный VPN, третья команда исключает приложение из ограничений device idle. Я применил все три до запуска. После этого v2rayNG поднял tun0, использовал ядро Xray 26.6.27 и смог подключаться при старте.

Подписку я передал приложению интентом. В команду подставляется URL, уже закодированный для передачи в URI, поэтому адрес своего сервера в тексте и в команде не нужен:

`am start -a android.intent.action.VIEW -d "v2rayng://install-sub://<urlencoded_url>" com.v2ray.ang`

Если нужен одиночный профиль, приложение принимает его как текст через отдельную activity:

`am start -a android.intent.action.SEND -t text/plain --es android.intent.extra.TEXT "<uri>" com.v2ray.ang/.ui.UrlSchemeActivity`

Подписка умеет Hysteria2, VLESS Reality и Trojan. В моём рабочем профиле использован Hysteria2 и свой внешний сервер. Этого достаточно для описания схемы. Адрес, домен и порт сервера здесь ничего полезного не добавят.

В туннеле только SmartTube

Теперь важнее всего не включить VPN, а ограничить его. В интерфейсе v2rayNG я открыл дровер "Выбор приложений", включил режим выбора и поставил галочку только у org.smarttube.stable. Это пакет SmartTube 32.38. У него есть LEANBACK_LAUNCHER, поэтому значок остаётся в ТВ-лаунчере и приложение запускается пультом как обычное.

Интерфейс мог ошибиться, я мог нажать не туда. Поэтому проверка была не по значку VPN, а через состояние connectivity:

`dumpsys connectivity | grep VpnTransportInfo`

Система показала Uids: {10083}. В туннель попал только UID SmartTube. В этом и есть финальная проверка split tunneling: не предполагать, что выбор в UI сработал, а увидеть список в dumpsys.

С настройками на телевизоре есть ещё одна грабля. В v2rayNG чекбокс "Автоподключение" не реагировал на нажатие по самому квадрату. Root на устройстве недоступен, su и run-as тоже. Поэтому я смотрел структуру экрана через uiautomator dump, а не пытался выдать себе права, которых здесь нет:

`uiautomator dump /data/local/tmp/x.xml
cat /data/local/tmp/x.xml`

Дамп показывает tv_name, bounds и checked. Для навигации годятся события DPAD: 20 это вниз, 4 это назад, 23 это OK, 224 будит экран. Когда экран спит, снимок PNG имеет примерно 26 КБ и одинаковый размер, поэтому по нему нельзя понять, что сейчас на дисплее.

Практический ход простой: надо нажимать по правой части строки настройки, а не по самому чекбоксу. Для этого экрана с разрешением 1920x1080 рабочая точка была около 1840,342. Координата не является универсальным рецептом. Это результат разбора конкретных bounds, и на другом экране её нужно снять заново.

После включения "Автоподключение при запуске" начинает работать связка BootReceiver v2rayNG и BOOT_COMPLETED. Телевизор загружается, приложение получает событие и поднимает соединение. Если после ребута туннель не появился, достаточно открыть v2rayNG вручную один раз.

Порты, прокси и ещё одна потеря времени

В процессе я успел проверить несколько ложных следов. Порты 7382/7433/7434/20000/34299/36125 относятся к внутренней обвязке Салюта и для управления не подходят. 8008/8009 принадлежат Chromecast built-in. Для ADB нужен 5555, а 34893 из диалога нужен только для первичного handshake.

Ещё одна причина странных ошибок была не в телевизоре. Без этой настройки adb и curl пытались идти в локальный прокси и падали на 10061:

`export NO_PROXY="127.0.0.1,localhost,192.168.1.0/24"`

Это единственное место, где я указываю диапазон домашней сети. Он нужен лишь для исключения локального трафика из прокси. После этого подключение к ТВ в домашней сети перестало зависеть от настроек прокси на хосте.

Что я оставил на потом

Сейчас это тюнингованный Android TV с выборочным VPN. ADB даёт данные о памяти, позволяет остановить прожорливый процесс, поставить подходящий APK и проверить реальный маршрут трафика. При этом я не пытаюсь за один вечер удалить всё, что выглядит лишним.

Следующий этап - аккуратный деблоат. Сначала список сторонних пакетов:

`pm list packages -3`

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

`pm disable-user <pkg>`

Если пакет оказался нужен, вернуть его можно так:

`cmd package install-existing <pkg>`

Закрытая прошивка не приговор. В данном случае это просто Android, у которого забыли выключить ADB. Когда есть доступ к диагностике, телевизор перестаёт быть чёрным ящиком. Он остаётся устройством с ограниченной памятью и капризным интерфейсом, но у этой истории уже есть логи, команды и воспроизводимый результат.