Skip to content

Latest commit

 

History

History
257 lines (212 loc) · 40.3 KB

File metadata and controls

257 lines (212 loc) · 40.3 KB

Проверка релиза Message487

English | Русский

Проверяется конкретный подписанный APK-кандидат, затем опубликованный артефакт. Зелёный CI, успешный dry-run и тест подключения не заменяют проверку захвата на Android. Это регламент, а не отчёт о выполненных проверках.

Доказательства и статусы

Каждый сценарий на каждом устройстве получает PASS, FAIL, BLOCKED, NOT TESTED или N/A. N/A требует причины, связанной с продуктом или платформой; отсутствие устройства/времени — NOT TESTED. JVM-тест и анализ исходников не заполняют ячейку проверки на устройстве. Для частичного результата укажите, что именно выполнено.

Запись: ID сценария, время UTC, commit и SHA-256 APK, устройство/ОС, предусловия, действие, expected/actual, ссылки на доказательства, статус и результат восстановления. Для доставки сопоставьте синтетический маркер и event_id в Журнале, HTTP-запросе и n8n Executions; проверьте тело и статус ответа. Отрицательный сценарий требует исправного положительного контроля до и после. Существенные ошибки авторизации, утечки и потерю данных воспроизводите дважды с новыми маркерами.

accepted означает подтверждение веб-хука, а HTTP 2xx без ACK — только HTTP-успех. Они не подтверждают Telegram или другой последующий узел: его проверяют отдельно. Повторная отправка после потери ответа может создать несколько executions с одним event_id; Message487 не обещает exactly-once. Стенд и downstream должны дедуплицировать по ID, если это требуется сценарию.

Сырые логи, дампы БД/UI, сетевые захваты и n8n executions держите локально в каталоге 0700, чувствительные файлы — 0600. Даже URL веб-хука может содержать секрет. В Git включайте только проверенные обезличенные выдержки и синтетические фикстуры. Не отправляйте диагностическое письмо, не загружайте APK на VirusTotal, не публикуйте issues/релизы и не меняйте внешний F-Droid MR в рамках обычного тестового прогона.

Подготовка

ID Действия и доказательства
A01 Зафиксируйте commit кандидата, diff после прошлого релиза, versionName/code, min/target SDK, зависимости/toolchain и точный источник APK. Версия берётся из app/build.gradle.kts, подпись — из scripts/build-release-apk.sh. Сохраните чужие изменения; не увеличивайте production versionCode ради теста.
A02 Выполните bundle exec fastlane android checks, PYTHON=.venv/bin/python bundle exec fastlane android python_checks; после запуска локального n8n — bundle exec fastlane android server_tests. Сохраните статусы и ссылки CI именно кандидата. Нет signing-переменных в PR-проверках. Инструкции окружения — в Тесты и CI.
A03 Выполните bundle exec fastlane android release_artifacts либо получите подписанный артефакт режима сборки без публикации. Сохраните SHA256SUMS, вывод apksigner verify --verbose --print-certs, aapt dump badging, permissions/merged manifest. APK должен быть release, нужного пакета/версии, с прежним ключом. Debug APK не заменяет этот шаг.
A04 Сверьте исходный и merged manifest, FileProvider, exported-компоненты, backup/data extraction, ограничения HTTP, разрешения зависимостей и изменения лицензий. Объясните RECEIVE_SMS, notification listener, POST_NOTIFICATIONS, REQUEST_INSTALL_PACKAGES и компоненты планировщиков. Не требуются SMS history, default SMS role, Accessibility, QUERY_ALL_PACKAGES. Сверьте описание/PRIVACY с поведением.
A05 Опишите два телефона и два выделенных эмулятора: модель, ОС/API/OEM build/patch, ABI/размер страницы, экран/шрифт/язык, пакет/версия/подпись/installer, разрешения, батарея, сеть, VPN/Private DNS. Эмуляторы — минимальный поддерживаемый API и современный. Если Samsung недоступен, OEM-проверка остаётся NOT TESTED.
A06 На телефонах сохраните исходные настройки, используйте только синтетические SMS и выбранные тестовые приложения. Не включайте захват личных приложений/OTP. Не удаляйте существующую установку и не очищайте её данные. Перезагрузка, смена сети/PIN и разрушительные проверки требуют применимого разрешения; выполняйте их сначала на выделенном эмуляторе.
A07 Поднимите закрытый HTTPS-стенд с доверенным сертификатом, отдельными токенами и контролируемыми ответами. Проверьте стенд прямым запросом. Локальный DevServer — HTTP/debug-фикстура, не проверка release HTTPS; для кандидата нужен HTTPS-вход. Не публикуйте стенд с общедоступными тестовыми реквизитами. Запишите ресурсы для последующей очистки.

Порядок выполнения

  1. Выберите commit кандидата и предыдущий подписанный релиз для миграции. Сохраните git status, git rev-parse HEAD и diff; работайте в отдельном чистом checkout, если в рабочем каталоге есть чужие изменения. Для теста до выпуска используйте подписанный кандидат, а не последний опубликованный APK с постоянной ссылки.
  2. Подготовьте JDK 21, Ruby/Bundler, Android SDK из Gradle-конфигурации, Platform Tools, Python и Docker. SDK задайте через ANDROID_HOME или локальный local.properties. Для Python: python3 -m venv .venv, затем .venv/bin/python -m pip install -r requirements-dev.txt; для Ruby — bundle install.
  3. Запустите локальный стенд: docker compose -f DevServer/compose.yaml up -d --wait --wait-timeout 300. Выполните команды A02. Это проверка фикстур; для signed release настройте закрытый HTTPS-вход с сертификатом, которому доверяет телефон, и отдельной авторизацией.
  4. Соберите кандидат командой A03, используя прежний ключ и signing-конфигурацию MESSAGE487_KEYSTORE_PATH, MESSAGE487_KEY_PASSWORD_FILE, MESSAGE487_KEY_ALIAS. Не печатайте пароли. Проверьте dist/release/SHA256SUMS; каждый последующий результат должен ссылаться на hash установленного кандидата. При F-Droid-канале выполните отдельный официальный build ниже и идентифицируйте его артефакт.
  5. Для каждого устройства запишите serial/параметры и исходные настройки. Выберите нужный serial в adb -s SERIAL; установите кандидат через adb -s SERIAL install -r /path/to/candidate.apk. Чистая установка допустима только на пустом тестовом устройстве/профиле. Сохраните adb -s SERIAL shell pm path life.andre.message487, скачайте выведенный путь через adb -s SERIAL pull и сравните SHA-256. Для migration сначала установите старый signed APK и создайте тестовую очередь.
  6. На экране Подключение задайте полный опубликованный webhook URL, токен без префикса Bearer и синтетический код устройства; включите n8n confirmation только для стенда с описанным ниже ACK. Нажмите Save/send test, сопоставьте ID в Журнале и серверном execution. Затем отдельно разрешите SMS/notification access и выберите только тестовые приложения; выполните I/C/Q/L/D/U, фиксируя матрицу по устройствам.
  7. После каждого отрицательного сценария верните рабочий стенд и подтвердите доставку новым маркером. В конце восстановите устройства, заполните отчёт и решение. R01/R02 не выпускают версию; R03 выполняется только после отдельно разрешённой публикации.

Контракт тестового сервера

Сервер принимает POST с Content-Type: application/json и Authorization: Bearer <тестовый токен>. JSON содержит schema_version, event_id, device_id, device_code, message_type, occurred_at, source, source_name, text; уведомление добавляет title, SMS — sender. Сохраните эти поля и время приёма в закрытом журнале стенда. Для каждой пробы используйте новый синтетический маркер.

При включённом n8n confirmation успешный ответ — HTTP 2xx и {"status":"accepted","event_id":"ID_ИЗ_ЗАПРОСА"}. Такой ACK настраивается workflow, а не возникает автоматически от самого n8n. При выключенном confirmation достаточно 2xx. Подготовьте управляемые режимы: корректный ACK, 500, 401/403, чужой event_id, malformed JSON, задержка дольше клиентского timeout и приём запроса с потерей ответа. Запись успешного execution без проверки HTTP-ответа не доказывает принятие клиентом.

Для раздельной проверки адресатов используйте endpoints A/B с разными тестовыми токенами. Положительный контроль отправляйте через приложение, а не только curl. На эмуляторе adb -s SERIAL emu sms send +15551234567 'Message487 synthetic RUN-ID' даёт отдельную пробу SMS broadcast. Для уведомлений основная проверка — обычное приложение, создающее уведомление с известными полями и собственным UID; shell/root используется только дополнительно. Оба пути должны подтверждаться реальным серверным запросом.

F-Droid и происхождение APK

В fdroiddata выберите build block именно кандидата для life.andre.message487, зафиксируйте recipe SHA, upstream SHA, fdroiddata/fdroidserver revisions, Binaries и AllowedAPKSigningKeys, если заданы. Для внешнего MR проверяйте его текущее состояние; при независимом review требуется соответствующее приглашение к review. Существующий опубликованный рецепт тоже допустим как цель проверки; не заменяйте его предполагаемым новым build block.

Используйте официальный registry.gitlab.com/fdroid/fdroidserver:buildserver, запишите фактический digest/platform, штатного пользователя сборки и конфигурацию fdroiddata. В отдельном checkout выполните применимые команды поддерживаемой версии fdroidserver:

fdroid readmeta
fdroid lint life.andre.message487
fdroid fetchsrclibs life.andre.message487:VERSION_CODE --verbose
fdroid build --verbose --test --scan-binary --on-server --no-tarball life.andre.message487:VERSION_CODE

VERSION_CODE заменяется кодом из выбранного recipe. Объясните отличие команды, если его требует официальное окружение. Сохраните exit codes, source/binary scanner results и путь APK. Не изменяйте recipe для получения PASS. Предупреждения исследуйте, а не объявляйте автоматически блокерами; отдельно проверьте updater/APK downloads, зависимости, бинарные assets и применимость Inclusion Policy.

При воспроизводимой сборке выполните официальный механизм binary comparison/signature-copy с точным upstream APK и разрешённым сертификатом. Обычный Gradle build и сравнение SHA-256 APK с разными подписями не заменяют эту проверку. Руководство F-Droid. Если matching upstream APK ещё не опубликован, проверка BLOCKED/NOT TESTED; не публикуйте релиз только ради теста и не объявляйте воспроизводимость заранее.

Для runtime установите именно проверенный подписанный APK; локальный unsigned результат не обновляет прежнюю signed установку. Если проверяется подпись F-Droid, идентифицируйте её отдельно. Прочитайте установленный APK через pm path/adb pull и сверяйте hash с ожидаемым артефактом на каждом устройстве. Реальная установка клиентом F-Droid нужна для проверки источника обновлений; установка через ADB не доказывает этот путь.

Матрица устройств

Сценарии ниже выполняйте на всех четырёх устройствах, где применимы. Для сценария, недоступного на телефоне, не подставляйте PASS эмулятора. Деструктивные сбои БД/Keystore, подмену APK/времени, process kill, Doze и искусственные ответы сначала проверяйте на выделенном стенде. На телефоне без возможности SMS используйте N/A с причиной; эмуляторная SMS не доказывает доставку от оператора.

Установка, разрешения и UI

ID Действие → требуемый результат
I01 Чистая установка в пустой эмулятор/тестовый профиль; два холодных запуска. Захват SMS и уведомлений выключен, приложения не выбраны; без настройки нет отправки личных данных. Автопроверка обновлений — отдельная функция, её запросы учитывайте отдельно.
I02 Установите предыдущий signed релиз, сохраните синтетические URL/токен/код устройства, выбор источников и недоставленные события, затем обновите до кандидата без удаления. Сохраняются настройки, installation ID, пауза, очередь и старые адресаты; выполните новую доставку и доставку старой очереди. Переустановка той же версии не является миграцией.
I03 Отказать → выдать → отозвать RECEIVE_SMS и notification access. Нет захвата отключённого источника, нет падения/ложного статуса; повторное разрешение восстанавливает захват только новых событий. Разрешение обычных уведомлений относится к напоминаниям обновлений, а не notification listener.
I04 Restricted settings после APK-install: официальный путь разрешения, повторное открытие notification access. На Samsung — Auto Blocker при первой установке и обновлении, возврат защиты после теста. См. установку APK. Не считать разрешение unknown sources решением любой блокировки.
I05 Обзор/Подключение/Источники/Журнал/Диагностика/Обновления; Back/Home, rotation, узкий экран, большой шрифт, EN/RU, светлая/тёмная тема, клавиатура, внешний/внутренний экран складного телефона. Действия и длинные диалоги доступны. Цветная и themed launcher icon проверяются реальным переключателем лаунчера, где поддерживается.

Захват и управление источниками

ID Действие → требуемый результат
C01 Обычное тестовое приложение с собственным UID публикует выбранное уведомление; независимая сверка title/text/time/package/source_name на сервере. Повторить с невыбранным приложением: нет события. Shell notification — дополнительная проба, не замена обычного UID.
C02 Обычный текст, big text, строки InboxStyle, пустое содержимое, ongoing и group summary; обновление текста уведомления. Исключённые ongoing/summary/свои уведомления не пересылаются. Уже существующее уведомление при выдаче доступа не воспроизводится. Не обещать доступ к скрытому Android содержимому.
C03 Выбор/снятие приложения, ручной пакет без launcher, поиск и «Выбрать все». Массовый выбор действует на весь список, сохраняет ручные пакеты; установленное позже приложение не выбирается само. UI-перезапуск сохраняет выбор. Не выбирайте приложение, получающее downstream сообщения: возможен цикл.
C04 На телефоне получите синтетическую SMS с другого разрешённого тестового номера. Проверьте sender/text/occurred_at и source android; история SMS не импортируется, приложение не становится default SMS и не отправляет ответ. Отдельно — длинная multipart SMS, кириллица/Unicode и две разные SMS. Зафиксируйте сегментацию/время, а не только длину строки.
C05 Дедупликация SMS и уведомлений: оба переключателя включены по умолчанию; проверьте независимо все четыре сочетания, выключение/включение, перезапуск и перенос старой общей настройки при обновлении. Ключ — source package + точный text, время сравнивается в настраиваемом окне ± с включёнными границами. Проверьте обе границы и значения сразу за ними, нулевое окно (точное время), сохранение настройки после перезапуска и изменение окна. Одинаковые настоящие сообщения внутри окна тоже пропускаются. Изменение title/sender само по себе не меняет ключ. Управляемую идентичность события проверяйте фикстурой/JVM и отдельно runtime с доступными контролями; не выводите PASS из двух команд с разным временем.
C06 Отключение источника и пауза при захвате/отправке. Нет новых событий после отключения/паузы; пауза также задерживает старую очередь. Уже выполняющийся запрос может завершиться. После Resume старые события доставляются, пропущенные во время паузы не импортируются. Две ручные проверки подключения не должны подавляться дедупликацией сообщений.

Веб-хук, авторизация и очередь

ID Действие → требуемый результат
Q01 Save/send test, затем реальные capture events через HTTPS. Правильный Bearer в Authorization, JSON schema/поля, уникальный event_id и совпадающий ACK. Device code сохраняется, installation ID стабилен. Journal не показывает тело сообщения. Успех ручного test не доказывает RECEIVE_SMS или listener.
Q02 Правильный → неверный → отсутствующий/некорректный → восстановленный токен. Невалидный ввод не сохраняется; сервер отклоняет неправильный, UI не показывает принятие. Неверная TLS CA/hostname, self-signed без доверия и HTTP в release отклоняются. Редирект не пересылает тело/Authorization на новый адрес. Держите положительные контроли до/после.
Q03 n8n ACK: чужой/отсутствующий event_id, неверный status, malformed/слишком большой JSON; generic webhook с ACK выключенным. HTTP 2xx с неверным ACK — BLOCKED и ручной retry, а generic 2xx — HTTP_SUCCESS. Отличайте отказ клиента от успеха выполнения n8n error-workflow.
Q04 Timeout/network failure, HTTP 408/425/429/5xx → очередь повторяет; прочие HTTP failures → ручное исправление/retry. После восстановления сохраняются event_id, тело, старый URL/токен/ACK. Ответ потерян после приёма: возможен повтор на сервере, ID прежний. Нет обещания точного времени WorkManager retry.
Q05 Создайте offline очередь на endpoint A, смените настройку на B. Старые события идут только на A с прежними реквизитами; новые — на B. Ротация токена в UI не исправляет старый encrypted envelope. Используйте отдельные тестовые endpoints; при необходимости старые события явно удаляют, а не тихо перенаправляют.
Q06 Retry now, удаление тестовой записи, быстрые повторные действия и открытый detail при смене состояния. Нет дублирования локального события/потери очереди; активную отправку нельзя удалить как свободную запись. После acceptance payload удаляется из активной записи, metadata остаётся ограниченной; logical delete не доказывает физическое стирание.
Q07 Offline enqueue → обычное завершение процесса/rotation/relaunch → восстановление сети. Проверить сохранность encrypted payload и доставку, включая очередь предыдущей версии. Недоступный Keystore/повреждённое хранилище — изолированный сценарий: нет отправки мусора или тихого удаления; ошибка видна. Успех Robolectric не доказывает настоящий Keystore.

Жизненный цикл и фон

ID Действие → требуемый результат
L01 Home, блокировка экрана, удаление задачи и возвращение: новый capture и доставка с серверным доказательством. Два цикла сервер unavailable → available и offline → online; отдельно реальный Wi-Fi → мобильная → Wi-Fi на телефоне. ADB reverse/виртуальная cellular не доказывают handover оператора.
L02 На выделенном эмуляторе отдельно process death и am force-stop. Force-stop — системная остановка, не креш. После неё открыть приложение и проверить восстановление сохранённой очереди; не обещать захват событий, потерянных пока Android держал пакет stopped. Настоящий LMKD/OOM — отдельная проверка.
L03 Reboot при доступной/недоступной сети, разблокировка и новая SMS/notification; delivery recovery и источник/расписание обновлений сохраняются. Работу до первого unlock не считать обещанной: компоненты не заявлены directBootAware. Пробу в RUNNING_LOCKED фиксировать отдельно от результата после unlock.
L04 Forced Doze и OEM battery restriction, затем восстановление нормального режима; pending сохраняется, доставка возобновляется. Записать actual idle/exemption/network и длительность. Forced job не доказывает естественное суточное расписание. Foreground/background soak — не менее 15 минут с несколькими событиями; более длительные/суточные прогоны отмечать отдельно.
L05 Обновление APK при очереди и включённых источниках, затем при паузе. Сохраняется decryptability/адресат/состояние; пауза не снимается, источник не включается сам. Проверить новые события после установки и listener reconnect.

Приватность и диагностика

ID Действие → требуемый результат
D01 Синтетические маркеры в body/title/sender/URL/token/device code/ID/response. Искать в app logs, crash file, ZIP и доступных системных логах; нет утечки исключаемых полей. Часть private preferences и delivery metadata не имеет дополнительного шифрования — сверять с PRIVACY, а не обещать полное шифрование данных. Проверка SQLite/Keystore только на разрешённом стенде.
D02 Диагностика refresh/clear/ZIP/email chooser, Cancel и отсутствие mail app. Очистка логов не удаляет очередь. FileProvider даёт временное чтение выбранного вложения без произвольного доступа к данным/записи. Остановитесь на редакторе письма, ничего не отправляя.
D03 На выделенном эмуляторе вызвать app crash и повторный запуск: prompt, crash file, ZIP. Debug injection — отдельное доказательство, не PASS release-candidate crash handling. Проверить release crash, если воспроизводимый механизм доступен. ANR/native crash/kill не считать обработанными Java handler. Сопоставить logcat, exit reason и действия.
D04 Обычным probe APK попробовать чужие intents/broadcasts/provider access: нет доступа к секретам, управления приватными update actions или подделки SMS защищённому receiver. Проверить BIND_NOTIFICATION_LISTENER_SERVICE/BROADCAST_SMS/BIND_JOB_SERVICE и merged components. Shell UID/root не доказывают изоляцию от обычного приложения.

Обновления и релизный флоу

ID Действие → требуемый результат
U01 Реальные установки официальным/сторонним F-Droid клиентом, браузером/файловым менеджером, неизвестным установщиком; ручной выбор. Источник следует installer и поддержке repo links, выбор сохраняется. Просто установленный F-Droid не меняет browser installation. 404/offline не переводят на другой источник. Подмена installer metadata — только моделирование.
U02 Новая/та же/старая/повреждённая metadata; consent/Cancel download, ошибка/обрыв/size/digest/package/version/signer. Без согласия нет APK download, проверка обновлений от согласия не зависит. Неверные APK сначала JVM/изолированный эмулятор. Fixture-версии не публиковать и production versionCode не менять ради проверки.
U03 GitHub download → отдельное Install, отказ/выдача unknown-source permission, возврат из Settings, Cancel/успех, rotation/background. Сверить установленную версию/hash/подпись и доставку после установки. F-Droid открывает страницу, установку выполняет клиент. Разные подписи не обновляют друг друга; не удалять приложение как первое «исправление».
U04 Reminder permission/channel, Open/Skip/Disable, manual check после Skip, выключение при running job, reboot. Проверить повтор через неделю и отсутствие раннего повторения управляемым временем на эмуляторе. Принудительный запуск и simulation не считать естественным daily/weekly результатом.
R01 Dry-run с явно заданной предполагаемой версией: генерация EN/RU и проверки чтения, без файлов/релизной ветки/PR/merge/tag/Release. Пустое поле CI означает обычный CI. Перед/после сравнить refs/PR/releases; mock-тест и live run отметить отдельно. Dry-run не доказывает права записи, signing или прохождение ruleset.
R02 Перед реальным выпуском прочитать EN/RU changelog, сравнить versionName/code, историю и список файлов релизного PR. Gate должен ждать полный CI конкретного head/base; старый/skipped CI не принимается, изменённый main/head останавливает merge. Эти отказные случаи тестировать локально с mocks, не ломая production правила.
R03 Только после отдельного запуска выпуска проверить фактический merged commit/tag, tree и источник опубликованных APK, checksum/подпись, постоянный и versioned URL, changelog обеих локалей. Сверить APK с проверенным кандидатом; различающийся артефакт требует расследования/retest. F-Droid build/publication подтверждается отдельно.

Завершение и решение

Сначала APK identity, доставка test/SMS/notification на каждом устройстве, отрицательная авторизация/ACK, offline recovery и migration. Затем фон, updater, приватность и OEM/UI. При сокращении матрицы оставляйте NOT TESTED; оно не становится PASS. Для небольшого follow-up опишите diff, обязательные соседние регрессии и границы сокращённого прогона. Старые phone results не переносите на новую версию даже при неизменённом UI.

В конце остановите только созданные стенды/captures, удалите только свои ADB forwards/reverses, probe APK и синтетические события; верните сеть, permissions, источник/автопроверку, батарею, экран/шрифт/язык, Auto Blocker и исходные настройки приложения. Не удаляйте чужие workflow/volumes и личные сообщения. Удаление локального события не удаляет копию из n8n/downstream: очистите синтетические executions отдельно. Запишите остаточные изменения и проверьте устройства после восстановления.

Не рекомендовать выпуск при потере очереди/секретов, неверной подписи, обходе авторизации, утечке исключаемых данных, необъяснённых падениях или неработающем захвате/доставке на поддерживаемом устройстве. Критическая непроверенная миграция или BLOCKED gate означают РЕЛИЗ НЕ ПРОВЕРЕН. Для каналов GitHub и F-Droid фиксируйте отдельную готовность. Исправление: минимальная отдельная ветка, воспроизведение/регрессионный тест, новый APK, повтор affected и соседних сценариев; старый FAIL остаётся до retest.

Отчёт — docs/reviews/release-YYYY-MM-DD.md, только обезличенный материал:

Кандидат: commit, версия/код, SHA-256, сертификат, канал/происхождение APK
Окружение и устройства: фактические параметры и ограничения
Команды/CI/F-Droid: версии инструментов, recipe/image digest, результаты
Матрица: ID | устройство | PASS/FAIL/BLOCKED/NOT TESTED/N/A | доказательства
Находки: expected/actual, серьёзность, контроли, функция, retest commit/APK
Восстановление: ресурсы, что удалено/возвращено, остаточные изменения
Решение: готовность GitHub/F-Droid, blockers и непроверенные сценарии

До публикации устройство должно проверять подписанный кандидат из релизного PR; для проверки changelog до merge нужен human review gate в релизном флоу. Постпубликационный R03 — дополнительная проверка, а не разрешение выпускать непроверенный APK. В рамках подготовки этого регламента тесты на устройствах не выполнялись.

Свидетельства CI для кандидата

Запишите точные head/base PR, URL CI, отдельные результаты API 26/35, JUnit Checks, ссылку на APK и SHA-256. Ссылки обновляются в описании PR; неподписанные PR APK и тесты debug на эмуляторах не подтверждают приёмку подписанного релизного кандидата. Новому коммиту нужен новый CI; skipped или отсутствующие результаты эмуляторов блокируют финализацию.