Chrono Mock
ЯзыкРусский

Веб-страницы внутри нативного приложения

Настольное приложение со встроенным веб-движком запускает свои страницы в отдельном изолированном процессе. Нативный механизм покрывает приложение и останавливается на этой границе — поэтому окно переходит на запрошенную вами дату, а панель внутри него нет. Это закрывает такой пробел.

Сбой, который выглядит как успех

Множество приложений Windows снаружи нативные, а внутри — веб-страница. Экран настроек, дашборд, просмотр отчёта, панель лицензии — сделанные один раз на HTML и размещённые в WebView2 или Qt WebEngine, а не написанные дважды.

Движок запускает эти страницы в собственном процессе, и этот процесс изолирован. Библиотека, внедрённая в приложение, в него не попадает. Всё, что приложение запрашивает у Windows, переходит на дату сессии, а всё, что страница запрашивает у JavaScript, — нет:

  • Строка заголовка, логи и файлы говорят 2038.
  • Панель в том же окне говорит сегодня.
  • Ничего не падает, ничего не предупреждает, и обе половины выглядят одинаково уверенно.

Это дорогая версия такой ошибки, потому что тест как будто прошёл. Прежнее поведение сообщало о такой сессии как о чистом успехе — утверждение, которое инструмент не мог подкрепить.

Что делает сессия вместо этого

Сессия запускает оба механизма одновременно. Нативный хук входит в приложение как обычно, а до страниц добираются единственным способом, которым вообще добираются до изолированного рендерера: спрашивая сам движок.

При запуске приложение наследует две переменные среды, которые просят его движок открыть локальный порт отладки. Они добавляются к ключам, которые приложение и так передаёт, а не заменяют их. Затем сессия следит за собственными процессами, пока этот порт не появится, и когда он появляется, каждая страница и каждый worker за ним переходят на те же часы, что и приложение.

Один старт, одна скорость, одна временная шкала. Смена скорости или скачок доходят до приложения и его страниц вместе, а таймеры страниц идут в темпе приложения, а не в собственном.

Это включено по умолчанию и отключается одним переключателем, который не открывает никакого порта и оставляет страницы на настоящих часах.

# Ничего настраивать не нужно — движок находится, если он есть
chrono run "C:\Program Files\YourApp\YourApp.exe" --at 2038-01-01T00:00:00 --mode x60

# Или не трогать страницы и не открывать порт
chrono run "C:\Program Files\YourApp\YourApp.exe" --at 2038-01-01T00:00:00 --no-embedded

Что отчёт говорит о страницах

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

  • В заголовке считаются оба — processes: 4, contexts: 1.
  • У каждой страницы свои строки, например context 1: page Date.now (12 calls) в командной строке и page Date.now - fake clock в таблице аудита в окне.
  • Достигнутый движок называется вместе с портом, так что вы можете направить собственные DevTools ровно на те страницы, которыми управляет сессия.

Пробный запуск (dry run) сообщает, будут ли достигнуты страницы, до того, как что-либо запущено. Что означают вердикты →

Три ограничения, о которых стоит знать до начала

Порт отладки остаётся открытым, пока работает движок.

Он слушает только на этом компьютере, но открыт для любой программы на этом компьютере, пока работает движок, и всё, что до него доберётся, может управлять этими страницами. Сессия предупреждает об этом каждый раз, когда порт был открыт, и называет порт, а не упоминает его вообще. На общей или недоверенной машине используйте переключатель, который ничего не открывает.

Приложение, запущенное с повышенными правами, недосягаемо.

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

Такая сессия сообщает PARTIAL, и это честный ответ.

Вспомогательные процессы движка и собственные нативные вызовы времени рендерера остаются на настоящих часах. Страницы на часах сессии, остальная часть семьи — нет, поэтому вердикт говорит частично и называет то, что осталось за бортом, а не округляет вверх до успеха.

Ещё два, поменьше, сказанные прямо. Страницы читают часовой пояс сессии как фиксированное смещение, поэтому Intl называет его смещением, например GMT+02:00, а не городом. А таймер, поставленный в расписание до того, как сессия достигла страницы, сохраняет прежний темп — так же, как в чистой сессии Chromium; сессия предупреждает, а не позволяет сделать вывод, что ничего не произошло.

Если движок настроен политикой аргументов браузера в реестре, переменная сессии имеет приоритет на время её работы, и отчёт об этом сообщает — потому что порт отладки, настроенный там, не был бы применён.

Насколько хорошо это проверено

Экспериментально, с тем же определённым смыслом, что и в остальных местах: оно работает на тех целях, под которые создавалось, не проверялось широко, а встроенный аудит — ваш источник истины, а не эта страница. Измерено вручную на хосте WebView2 и хосте Qt WebEngine в 64-разрядной Windows, а не автоматическим набором. В этих запусках страницы читали год сессии в темпе сессии и следовали за скачком.

В 32-разрядной Windows есть нюанс, о котором лучше знать заранее, чем обнаружить: среда выполнения WebView2 64-разрядная, даже когда размещающее её приложение 32-разрядное, поэтому 32-разрядная сессия не может назвать процессы движка или их роли. Канал к страницам при этом работает. Отчёт просто менее конкретен в том, что ему не удалось определить, и говорит, какой из двух вариантов имеет место.

Попробуйте