Запись о ловушках Android 10 WebView
Запись о ловушках Android 10 WebView

Проект требует поддержки воспроизведения видео высокой четкости 8K (кодировка H265). После получения платы я обнаружил, что могу воспроизводить видео высокой четкости 8K с помощью приложения, но не с помощью браузера, даже если установлена ​​последняя версия Chrome для Android. . Основываясь на прошлом опыте разработки ядра браузера, на платформе Android Chromium WebView в конечном итоге вызывает MediaPlayer уровня системной инфраструктуры для воспроизведения. Теоретически, пока уровень системной инфраструктуры может поддерживать воспроизведение высокой четкости 8K, браузер также должен его поддерживать. Реальная ситуация не так, и предварительно скомпилированный WebView для Android 10 не имеет вывода журнала, поэтому вам необходимо загрузить исходный код для компиляции Chromium WebView, чтобы выяснить проблему.

Подводные камни выбора версии

Обновления исходного кода Chromium очень обыденны, а архитектура часто меняется. В отличие от наших проектов, набор кода можно исправлять и использовать более десяти лет. Предыдущий проект был настроен на основе Chromium V53. На этот раз я не хотел использовать последнюю версию Chromium. Я кратко просмотрел последний исходный код и обнаружил, что он сильно отличается от V53. Переносить предыдущую версию было довольно сложно. работа. Первое, что приходит на ум — использовать исходный код V53 напрямую, но его нельзя применить к Android 10. Основная причина в том, что интерфейс WebView API Android 10 претерпел некоторые изменения. Что окончательно заставило меня сдаться, так это то, что из уровня платформы Android 10 был удален класс HardwareCanvas. Знаете, в Android 5.1 в WebView есть важный метод рисования:

Язык кода:javascript
копировать
public void callDrawGlFunction(Canvas canvas, long nativeDrawGLFunctor) {
    if (!(canvas instanceof HardwareCanvas)) {
        // Canvas#isHardwareAccelerated() is only true for subclasses of HardwareCanvas.
        throw new IllegalArgumentException(canvas.getClass().getName()
                + " is not hardware accelerated");
    }
    ((HardwareCanvas) canvas).callDrawGLFunction2(nativeDrawGLFunctor);
}

V53 использовать нельзя. Далее рассмотрим предварительно скомпилированную версию Chromium Webview в Android 10. Используйте оболочку WebView, чтобы просмотреть номер версии 74.0.3729.183:

Однако здесь есть огромная дыра. После того, как я потратил немало усилий на загрузку кода, компиляцию Chromium WebView и установку его в систему, браузер вылетел при запуске. Проверив системный журнал, я обнаружил следующее сообщение об ошибке:

Язык кода:javascript
копировать
03-05 00:41:09.457  3299  4011 W WebViewUpdater: creating relro file timed out
03-05 00:41:09.458 12565 12565 E WebViewFactory: Chromium WebView package does not exist
03-05 00:41:09.458 12565 12565 E WebViewFactory: android.webkit.WebViewFactory$MissingWebViewPackageException: Failed to load WebView provider: No WebView installed
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.webkit.WebViewFactory.getWebViewContextAndSetProvider(WebViewFactory.java:339)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.webkit.WebViewFactory.getProviderClass(WebViewFactory.java:402)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:252)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.webkit.WebView.getFactory(WebView.java:2551)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.webkit.WebView.setWebContentsDebuggingEnabled(WebView.java:1974)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at org.chromium.webview_shell.WebViewBrowserActivity.onCreate(WebViewBrowserActivity.java:230)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.Activity.performCreate(Activity.java:7802)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.Activity.performCreate(Activity.java:7791)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.os.Handler.dispatchMessage(Handler.java:107)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.os.Looper.loop(Looper.java:214)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at android.app.ActivityThread.main(ActivityThread.java:7368)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at java.lang.reflect.Method.invoke(Native Method)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
03-05 00:41:09.458 12565 12565 E WebViewFactory:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
03-05 00:41:09.459 12565 12565 D AndroidRuntime: Shutting down VM

После проверки кода уровня платформы квалифицированный поставщик WebView сначала должен иметь номер версии targetSdk больше или равный 29, а также проверить файл build/config/android/sdk.gni исходного кода chromium v74:

Язык кода:javascript
копировать
# The default SDK release used by public builds. Value may differ in
# internal builds.
default_android_sdk_release = "p"

# SDK releases against which public builds are supported.
public_sdk_releases = [ "p" ]

Android 10 имеет кодовое название Q, что означает, что эта версия Chromium WebView на самом деле поддерживает только Android 9. Я не знаю, какую магию использовал Google. Возможно, в процессе разработки Android 10 для сборки использовался внутренний SDK.

В настоящее время я все еще не хочу использовать последнюю версию, поэтому просто используйте самую раннюю версию, которая официально поддерживает Android Q. Метод состоит в том, чтобы проверить запись модификации этого sdk.gni и посмотреть, какой коммит был изменен с «p» на «q». Поскольку в коде очень много ветвей, вы должны проверить git-коммиты всех ветвей:

Язык кода:javascript
копировать
$ git log -p  --all -G 'sdk' sdk.gni

Обнаружено, что идентификатор коммита — c2481863282a401926e0ee479334c68ec362d302. Далее проверьте, какие ветки содержат этот коммит:

Язык кода:javascript
копировать
$ git branch -a --contains c2481863282a401926e0ee479334c68ec362d302
  remotes/branch-heads/3967
  remotes/branch-heads/3968
  remotes/branch-heads/3969
  remotes/branch-heads/3970
  remotes/branch-heads/3971
  remotes/branch-heads/3972
  remotes/branch-heads/3973
  remotes/branch-heads/3974
  remotes/branch-heads/3975
  remotes/branch-heads/3976
  remotes/branch-heads/3977
  remotes/branch-heads/3978
  remotes/branch-heads/3979
  remotes/branch-heads/3980
  remotes/branch-heads/3981
  remotes/branch-heads/3982
  remotes/branch-heads/3983
  remotes/branch-heads/3984
  remotes/branch-heads/3985
  remotes/branch-heads/3986
  remotes/branch-heads/3987
  remotes/branch-heads/3987_100
  remotes/branch-heads/3987_137
  remotes/branch-heads/3987_158
  remotes/branch-heads/3987_87
  remotes/branch-heads/3988
  remotes/branch-heads/3989
  remotes/branch-heads/3990
  remotes/branch-heads/3991
  remotes/branch-heads/3992
  remotes/branch-heads/3993
  remotes/branch-heads/3994
  remotes/branch-heads/3995
  remotes/branch-heads/3996
  remotes/branch-heads/3997
  remotes/branch-heads/3998
  remotes/branch-heads/3999
  remotes/branch-heads/4000
  remotes/branch-heads/4001
  remotes/branch-heads/4002
  remotes/branch-heads/4003
  remotes/branch-heads/4004
  remotes/branch-heads/4005
  remotes/branch-heads/4006
  remotes/branch-heads/4007
  remotes/branch-heads/4008
  remotes/branch-heads/4009
  remotes/branch-heads/4010
  remotes/branch-heads/4011
  remotes/branch-heads/4012

Существует множество веток, содержащих эту публикацию. Чем больше число, тем новее код ветки, поэтому просто найдите стабильную версию в середине. Посетите следующую ссылку:

https://chromiumdash.appspot.com/releases?platform=Android

Здесь собраны все выпущенные версии. В итоге я выбрал. V80.0.3987.165 . пробираться через Яма для загрузки кода、компилироватьяма、Монтажная яманазад,Наконец успешно пробежал:

Яма для загрузки кода

По известным причинам исходный код Chromium невозможно загрузить напрямую. Для его загрузки я использовал прокси. Однако при загрузке часто возникает следующая ошибка:

Язык кода:javascript
копировать
remote: Counting objects: 867615, done
remote: Finding sources: 100% (10514569/10514569)
error: RPC failed; curl 56 GnuTLS recv error (-9): Error decoding the received TLS packet.
fatal: the remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

В Git нет механизма возобновления точки останова. Если загрузка не удалась, ее нужно перезапустить. При встрече со сверхбольшой библиотекой, такой как Chromium, загрузка прерывается, когда она достигает размера более десяти гигабайт. Я искал много методов в Интернете, но не помогло. Затем я нашел решение в сообщении:

Язык кода:javascript
копировать
git config --global http.postBuffer 5242880000
git config --global https.postBuffer 5242880000
sudo ifconfig eth0 mtu 9000

В Интернете обычно рекомендуется устанавливать для http.postBuffer относительно большое значение. Для одной библиотеки git, такой как Chromium, размер буфера превышает 30 ГБ, и, наконец, ошибок больше нет. Также есть инструкции по установке размера MTU равным 14000, но его невозможно установить в Ubuntu. Максимальное значение, которое я пробовал, было 9000.

После успешного клонирования исходного кода при выполнении команды gclient runhooks возникает следующая ошибка:

Язык кода:javascript
копировать
NOTICE: You have PROXY values set in your environment, but gsutilin depot_tools does not (yet) obey them.
Also, --no_auth prevents the normal BOTO_CONFIG environmentvariable from being used.
To use a proxy in this situation, please supply those settingsin a .boto file pointed to by the NO_AUTH_BOTO_CONFIG environmentvariable.

Это причина использования прокси. Решение очень простое. Создайте текстовый файл (например, $HOME/.boto) со следующим содержимым.

Язык кода:javascript
копировать
[boto]
proxy = IP-адрес прокси
proxy_port=порт прокси

Затем установите переменную среды NO_AUTH_BOTO_CONFIG, чтобы она указывала на этот файл:

Язык кода:javascript
копировать
export NO_AUTH_BOTO_CONFIG=$HOME/.boto

На этом этапе проблема загрузки исходного кода и загрузки двоичных файлов окончательно решена.

Яма компиляции кода

Во время компиляции кода возникает следующая ошибка:

Язык кода:javascript
копировать
FAILED: gen/build/android/buildhooks/build_hooks_android_java.javac.jar gen/build/android/buildhooks/build_hooks_android_java.javac.jar.info 
python ../../build/android/gyp/javac.py --depfile=gen/build/android/buildhooks/build_hooks_android_java__compile_java.d --generated-dir=gen/build/android/buildhooks/build_hooks_android_java/generated_java --jar-path=gen/build/android/buildhooks/build_hooks_android_java.javac.jar --java-srcjars=\[\] --java-version=1.8 --full-classpath=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:deps_info:javac_full_classpath\) --interface-classpath=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:deps_info:javac_full_interface_classpath\) --processorpath=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:javac:processor_classpath\) --processors=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:javac:processor_classes\) --java-srcjars=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:deps_info:owned_resource_srcjars\) --bootclasspath=@FileArg\(gen/build/android/buildhooks/build_hooks_android_java.build_config:android:sdk_interface_jars\) --chromium-code=1 --errorprone-path bin/errorprone @gen/build/android/buildhooks/build_hooks_android_java.sources
Traceback (most recent call last):
  File "../../build/android/gyp/javac.py", line 595, in <module>
    sys.exit(main(sys.argv[1:]))
  File "../../build/android/gyp/javac.py", line 590, in main
    add_pydeps=False)
  File "/data/chromium/chromium_v74.0.3729.183/src/build/android/gyp/util/build_utils.py", line 653, in CallAndWriteDepfileIfStale
    pass_changes=True)
  File "/data/chromium/chromium_v74.0.3729.183/src/build/android/gyp/util/md5_check.py", line 87, in CallAndRecordIfStale
    function(*args)
  File "/data/chromium/chromium_v74.0.3729.183/src/build/android/gyp/util/build_utils.py", line 638, in on_stale_md5
    function(*args)
  File "../../build/android/gyp/javac.py", line 584, in <lambda>
    lambda: _OnStaleMd5(options, javac_cmd, java_files, classpath),
  File "../../build/android/gyp/javac.py", line 350, in _OnStaleMd5
    stderr_filter=ProcessJavacOutput)
  File "/data/chromium/chromium_v74.0.3729.183/src/build/android/gyp/util/build_utils.py", line 227, in CheckOutput
    raise CalledProcessError(cwd, args, stdout + stderr)
util.build_utils.CalledProcessError: Command failed: ( cd /data/chromium/chromium_v74.0.3729.183/src/out/Default; bin/errorprone -g -encoding UTF-8 -sourcepath : -XepDisableAllChecks -source 1.8 -target 1.8 -Xlint:unchecked -Werror -bootclasspath lib.java/third_party/android_tools/android.interface.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar -d /tmp/tmpzNZrEr/classes @/tmp/tmpzNZrEr/files_list.txt )
-Xbootclasspath/p is no longer a supported option.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Причина в том, что Ubuntu 20.04 использует JDK версии 11, но для этой версии компиляции Chromium требуется JDK 8. Решение состоит в том, чтобы переключить JDK на JDK:

Язык кода:javascript
копировать
$ java --version
openjdk 11.0.18 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu120.04.1)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu120.04.1, mixed mode, sharing)
$ sudo update-alternatives --config java
[sudo] password for alex: 
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      auto mode
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      manual mode
  2            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode

Press <enter> to keep the current choice[*], or type selection number: 2
update-alternatives: using /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode
$ java -version
openjdk version "1.8.0_362"
OpenJDK Runtime Environment (build 1.8.0_362-8u362-ga-0ubuntu1~20.04.1-b09)
OpenJDK 64-Bit Server VM (build 25.362-b09, mixed mode)

После переключения JDK system_webview_apk был успешно скомпилирован.

Яма для установки WebView

После компиляции system_webview_apk и его установки возникает следующая ошибка:

Язык кода:javascript
копировать
Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package com.android.webview signatures do not match previously installed version; ignoring!]
- Performing Streamed Install

Это вызвано несоответствием сертификата, используемого для компиляции Chromium, и сертификата платформы Android 10. Способ решения этой проблемы — сделать сертификаты с обеих сторон одинаковыми.

Первый шаг — проверить информацию подписи weview.apk в Android 10. Используйте инструмент сжатия, чтобы распаковать файл META-INF/WEBVIEW-.RSA в APK, а затем используйте следующую команду для просмотра информации о подписи:

Язык кода:javascript
копировать
$ keytool -printcert -file META-INF/WEBVIEW-.RSA

Второй шаг — определить сертификат, используемый Android 10. Обычно используется сертификат в папке build/target/product/security/. Некоторые продукты также используют специальные сертификаты, которые обычно размещаются в каталоге продукта под устройством. А что, если ты уверен? Проверьте информацию о подписи сертификата, она должна совпадать.

Язык кода:javascript
копировать
openssl x509 -in testkey.x509.pem -noout -fingerprint

Третий шаг — импорт хранилища ключей. Chromium использует формат хранилища ключей, который широко используется в Java, поэтому сертификат в Android 10 необходимо импортировать.

Язык кода:javascript
копировать
# Формат закрытого ключа pkcs8 изменять PEM
$ openssl pkcs8 -inform DER -nocrypt -in $ANDROID_SOURCE/build/target/product/security/testkey.pk8 -out testkey.pem
# Сертификат от PEM изменять pkcs12
$ openssl pkcs12 -export -in $ANDROID_SOURC/build/target/product/security/testkey.x509.pem -inkey testkey.pem -out testkey.p12 -name "android_testkey"
Enter Export Password: (Введите пароль android, по умолчанию — android, если вы делаете свой ключ, введите соответствующий пароль)
Verifying - Enter Export Password: (введите пароль андроид)
# генерировать keystore
$ keytool -importkeystore -deststorepass android -destkeypass android -srckeystore testkey.p12 -srcstoretype pkcs12 -srcstorepass android -destkeystore AOSP.keystore -alias android_testkey

Четвертый шаг — изменить gn args, использовать собственное хранилище ключей, изменить файл out/Default/args.gn и добавить следующие строки:

Язык кода:javascript
копировать
# гипотеза AOSP.keystore Файл находится по адресу chromium src в каталоге
android_keystore_path = "//AOSP.keystore"
android_keystore_name = "android_testkey"
android_keystore_password = "android"

Пятый шаг — пересобрать system_webview_apk.

Язык кода:javascript
копировать
autoninja -C out/Default system_webview_apk

Повторная установка может пройти успешно.

Можно ожидать, что и в будущем будут встречаться подводные камни. Нет другого выхода, кроме как засыпать ямы при встрече с ними. Разве это не должностная обязанность программистов?

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose