Я являюсь обладателем Яндекс Станции Макс, Яндекс Модуля 2, Яндекс ТВ Станции и ряда "слепых" устройств вроде Станции Мини. Устройства приобретены за полную стоимость, активна подписка Яндекс Плюс, даже включен Яндекс Про - но я на стартовом экране почему-то вижу рекламу бесполезных мне приложений вроде Иви, а при просмотре ТВ каналов, тёплую и ламповую рекламу в эфире постоянно перебивает повторяющаяся и отличающаяся по громкости реклама от Яндекс. Поддержка Яндекс не смогла ответить как мне избавиться от вставляемой ими рекламы даже за деньги - так что помогу себе сам.
Для того, чтобы избавиться от рекламы потребуется устройство с правами root и отключенным selinux. В качестве примера опишу отключение рекламы на Яндекс Модуле 2, так как на нем проще всего получить root - например, на 4pda есть готовая инструкция. На других устройствах принцип отключения рекламы и сама утилита - те же самые. Отличается только метод получения root и установки автозапуска утилиты после перезагрузки.
Сперва немного теории.
В прошлой статье я рассказал как с помощью mitm proxy посмотреть трафик от устройства до серверов Яндекс. За "подгорающие" приложения отвечает json блок recentsConfig, находящийся внутри system_config в секции приложения com.yandex.tv.home, загружаемый с адреса https://quasar.yandex.net/get_sync_info?device_id=серийник:
конфиг довольно большой, написан в одну строку, поэтому я на скриншоте удалил лишнее и отформатировал:
Если посмотреть с помощью утилиты jadx в код приложения com.yandex.tv.home (YandexTvHome.apk), то поймем, что просто удалить данную секцию из конфига (например, перебив строку "pinnedItems" на, скажем, "boringItems", чтобы код приложения ее не нашел) не удастся - на экране все-равно влепят иконку телевизора в самое левое место:
Так что для отключения рекламы приложений надо вставить пустой блок "pinnedItems":{}, а не просто убрать его.
Я в своем коде делаю следующее: заменяю строку "pinnedItems" на "boringItems", а на место длинной строки "customAppIconsPackages" вставляю "pinnedItems":{},"zzzzz". Тем самым старое содержимое customAppIconsPackages станет объектом с именем zzzzz.
static const ReplaceRule backend_rules[] = {
{"\"pinnedItems\"", "\"boringItems\""},
{"\"customAppIconsPackages\"", "\"pinnedItems\":{},\"zzzzz\""},
};
Этот способ мне не нравится - если ваш конфиг не содержит раздел customAppIconsPackages, то в конфиг не добавится пустой "pinnedItems":{} на его место, а значит на экран будет добавлена иконка "ТВ" (слева), и иконка "Кинопоиска" (которая по мере запуска других приложений уйдет за правый край экрана).
Если кто-нибудь доработает мой код - будет отлично. Утилита tls_proxy работает аналогично mitm proxy, только написана на C и сертификаты в ней захардкожены.
Код, написан с помощью ИИ, поэтому прост, понятен и даже содержит комментарии.
Кстати, заметил, что в некоторых конфигах после следующего за "pinnedItems" двоеточия стоит пробел перед фигурной скобкой, а в некоторых - фигурная скобка идёт вплотную. Причем устройство одно и то же.
Второе место, которое раздражает - реклама, которую Яндекс пихает поверх эфирной:
Отвечает за нее сервис https://graphql.kinopoisk.ru/graphql?operationName=StreamsTVChannelAdvertisements. Приложения Яндекса отправляют туда POST запрос:
Приведу "query" целиком: "query StreamsTVChannelAdvertisements($contentId: String!, $includeStartingChannelData: Boolean!, $includeDataByContentId: Boolean!, $scheduleDuration: Duration!) { dataByContentId: content(contentId: $contentId) @include(if: $includeDataByContentId) { __typename ...streamsTvAdvertisementsFragment } startingChannelData: userProfile @include(if: $includeStartingChannelData) { userData { startingTvChannel { __typename ...streamsTvAdvertisementsFragment } } } clientInfo { time { currentTimeUtc } } } fragment streamsTvAdvertisementFragment on TvAdvertisement { __typename position ... on TvSdkAdvertisement { data { params type vendorClientId } } ... on TvUrlAdvertisement { urls } } fragment streamsTvAdvertisementsFragment on TvChannel { advertisements { __typename ...streamsTvAdvertisementFragment } tvPrograms(duration: $scheduleDuration, extraCount: 1) { id advertisements { __typename ...streamsTvAdvertisementFragment } startTime endTime } }"
Жирным выделена интересующая нас строка. Если ее "поломать", например, забив слово urls четырьмя пробелами - реклама пропадёт.
Просто заблокировать доступ к серверу graphql.kinopoisk.ru нельзя - с него же приложение получает ссылки на эфирные каналы https://graphql.kinopoisk.ru/graphql?operationName=StreamsTVChannelStreams
Также Яндекс добавляет рекламный баннер непосредственно в домашнее приложение:
Где-то я читал, что так происходит только на аккаунтах без Яндекс Плюс - но скриншот доказывает обратное. Баннер у меня вылезает очень редко, так что я не уверен, что угадал его причину, но в конфиге я вижу блок, подозрительно похожий на размеры этого баннера. Блок встречается в нескольких местах:
В утилите я просто меняю "height": "180" на "height": "0", тем самым, если реклама и будет загружаться, то высота баннера будет 0 пикселов и на экране я ее просто не увижу. Также внутри секции "includeGroups":{"minusUsers":true,"notLoggedUsers":true,"plusUsers":true} я меняю true на false для minusUsers и plusUsers, а notLoggedUsers просто выбросил, чтобы сохранить старую длину строки. Не знаю, что из этого помогло - но баннер я больше не вижу.
Конец теории.
Настраиваем Яндекс Модуль 2 для отключения рекламы.
Необходимые файлы и исходные тексты утилиты я выложил на свой git. Как обычно предупреждаю, что они проверялись только на моем личном устройстве и работу где-либо еще я не гарантирую. Так что используйте их на свой страх и риск.
Нужно распаковать содержимое архива yahome-no-ads.zip на рутованный (включая раздел 3 "для гиков") Яндекс Модуль 2 в папку /data/local/tmp (именно в эту папку, вложенные папки не поддерживаются - так как пути жестко прописаны в скриптах и утилите), после чего с root консоли проделать следующее:
cd /data/local/tmp
chmod +x *.sh
./patch_init_rc.sh
./myscript-9.sh
reboot
Скрипт patch_init_rc.sh перемонтирует корневую файловую систему устройства на read-write и допишет в конец init.rc строки, запускающие myscript-9.sh при каждой загрузке.
Первый запуск myscript-9.sh также перемонтирует файловую систему / в rw и добавит дополнительный корневой сертификат в /system/etc/security/cacerts.
Так как на Модуле 2 стоит старая версия Android, загружающая системные корневые сертификаты только при старте, то перезагрузка обязательна.
После перезагрузки реклама пропадет.
Приложение ведет лог в /data/local/tmp/proxy.log и скидывает проходящий через него трафик в файлы /data/local/tmp/traffic-client.bin и /data/local/tmp/traffic-backend.bin, при этом следит чтобы размер каждого файла не превышал 10 мб, чтобы случайно не забить внутреннее хранилище.
Обязательно отключите com.yandex.launcher.updaterapp (предварительно установив нужные вам приложения из маркета Яндекс), иначе будущие обновления системы вернут рекламу назад. Я это делаю таким образом (команды выполнять с root консоли):
mv /data/data/com.yandex.launcher.updaterapp /data/data/com.yandex.launcher.updaterapp1
touch /data/data/com.yandex.launcher.updaterapp
reboot
Архив содержит скрипт myscript-11.sh - я им пользуюсь на своей рутованной Яндекс ТВ Станции. На ней работает подмена папки сертификатов через bind mount, так что правка раздела /system не требуется. Автозапуск скрипта я на ТВ Станции настраиваю не через правку init.rc, а совсем другим способом, который опубликую позднее (этот способ позволяет устанавливать официальные обновления прошивки без потери прав root, так как никакие изменения в официальный образ не вносит). Сейчас этот скрипт приведен просто для информации.
Напомню, что могут быть устройства, в конфиге которых отсутствует строка "customAppIconsPackages", которую я использую как место под пустой раздел "pinnedItems":{}. В этом случае на экране появится иконка "ТВ" вместо рекламных приложений. Также заменяемые строки в теории могут попасть на границы http блоков - тогда приложение их просто не заметит и реклама останется.
Если кто-нибудь переделает мой код под такие случаи - это только приветствуется.