diff --git a/.ci.yaml b/.ci.yaml index 292b8c3534dca..636cccafb3bd9 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -54,7 +54,10 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "android_virtual_device", "version": "android_36_google_apis_x64.textpb"}, {"dependency": "avd_cipd_version", "version": "build_id:8719362231152674241"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] os: Ubuntu cores: "8" @@ -74,7 +77,10 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "android_virtual_device", "version": "android_36_google_apis_x64.textpb"}, {"dependency": "avd_cipd_version", "version": "build_id:8719362231152674241"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] os: Ubuntu cores: "8" @@ -95,7 +101,10 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "android_virtual_device", "version": "android_35_google_apis_x64.textpb"}, {"dependency": "avd_cipd_version", "version": "build_id:8733065022087935185"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] os: Ubuntu cores: "8" @@ -157,7 +166,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 device_type: none $flutter/osx_sdk : >- { @@ -174,7 +183,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 device_type: none cpu: arm64 $flutter/osx_sdk : >- @@ -194,7 +203,7 @@ platform_properties: ] device_type: none mac_model: "Macmini8,1" - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 tags: > ["devicelab", "hostonly", "mac"] $flutter/osx_sdk : >- @@ -212,7 +221,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -231,7 +240,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -247,7 +256,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14|Mac-15 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: x86 device_type: "mokey" @@ -258,7 +267,7 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14|Mac-15 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: arm64 device_type: "mokey" @@ -273,7 +282,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 device_os: iOS-18 $flutter/osx_sdk : >- { @@ -291,7 +300,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: x86 device_os: iOS-18 $flutter/osx_sdk : >- @@ -310,7 +319,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "none"} ] - os: Mac-14|Mac-15 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: arm64 device_os: iOS-18 $flutter/osx_sdk : >- @@ -425,7 +434,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab","hostonly"] @@ -787,7 +799,10 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:36v3"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] shard: framework_tests subshard: slow @@ -892,7 +907,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -912,7 +930,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -932,7 +953,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -952,7 +976,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -973,7 +1000,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -994,7 +1024,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -1015,7 +1048,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -1059,7 +1095,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -1081,7 +1120,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -1102,7 +1144,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] # TODO(fujino): delete once propagation from # https://github.com/flutter/flutter/issues/158521 completes. @@ -1127,7 +1172,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] tags: > ["devicelab", "hostonly", "windows"] @@ -1604,7 +1652,10 @@ targets: [ {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:17"} + {"dependency": "open_jdk", "version": "version:17"}, + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} ] task_name: android_java17_dependency_smoke_tests tags: > @@ -2136,6 +2187,7 @@ targets: - name: Linux web_skwasm_tests_2 recipe: flutter/flutter_drone + bringup: true # Failing: https://github.com/flutter/flutter/issues/178060 timeout: 60 properties: dependencies: >- @@ -3124,6 +3176,12 @@ targets: artifact: gallery__transition_perf drone_dimensions: > ["device_os=U","os=Linux", "device_type=mokey"] + dependencies: >- + [ + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} + ] - name: Linux_build_test flutter_gallery__transition_perf_e2e recipe: devicelab/devicelab_drone_build_test @@ -3136,6 +3194,12 @@ targets: artifact: gallery__transition_perf_e2e drone_dimensions: > ["device_os=U","os=Linux", "device_type=mokey"] + dependencies: >- + [ + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} + ] - name: Linux_build_test flutter_gallery__transition_perf_hybrid recipe: devicelab/devicelab_drone_build_test @@ -3148,6 +3212,12 @@ targets: artifact: gallery__transition_perf_hybrid drone_dimensions: > ["device_os=U","os=Linux", "device_type=mokey"] + dependencies: >- + [ + {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "ninja", "version": "version:1.9.0"} + ] # linux mokey benchmark - name: Linux_mokey flutter_gallery__transition_perf_with_semantics @@ -5492,7 +5562,7 @@ targets: tags: > ["devicelab", "ios", "mac"] task_name: ios_debug_workflow - os: Mac-15 + os: Mac-15.5|Mac-15.7 $flutter/osx_sdk : >- { "sdk_version": "17a5295f" @@ -5534,7 +5604,7 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery__transition_perf_e2e_ios drone_dimensions: > - ["device_os=iOS-18","os=Mac-14|Mac-15", "cpu=x86"] + ["device_os=iOS-18","os=Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7", "cpu=x86"] - name: Mac_ios animated_blur_backdrop_filter_perf_ios__timeline_summary recipe: devicelab/devicelab_drone diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..ade159ddabcb9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +name: ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + name: ๐Ÿงช Test + + env: + FLUTTER_STORAGE_BASE_URL: https://download.shorebird.dev + + steps: + - name: ๐Ÿ“š Git Checkout + uses: actions/checkout@v4 + with: + # Fetch all branches and tags to ensure that Flutter can determine its version + fetch-depth: 0 + + - name: ๐ŸŽฏ Setup Dart + uses: dart-lang/setup-dart@v1 + + - name: ๐Ÿ“ฆ Install Dependencies + run: | + dart pub get -C ./dev/bots + dart pub get -C ./dev/tools + + - name: ๐Ÿงช Run Tests + run: dart ./dev/bots/test.dart diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml deleted file mode 100644 index 351077e1f13ad..0000000000000 --- a/.github/workflows/files-changed.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -name: Generate Changed Files JSON - -on: - pull_request: - types: - - opened - - synchronize - -jobs: - generate-json: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Fetch base commit and origin/master - # Fetch what to compare the commit against - run: | - git fetch --no-tags --prune --depth=1 origin ${{ github.event.pull_request.base.sha }} - git fetch --no-tags --prune --depth=1 origin master - echo "FLUTTER_PREBUILT_ENGINE_VERSION=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_ENV" - - - name: Initialize Dart SDK - # This downloads the version of the Dart SDK for the current platform. - run: | - ./bin/dart --version - cd dev/tools && ../../bin/dart pub get - - - name: Write changed files to a JSON file - run: | - ./bin/dart run dev/tools/bin/get_files_changed.dart --since="${{ github.event.pull_request.base.sha }}" > changed_files.json - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: changed-files - path: changed_files.json diff --git a/.github/workflows/shorebird_ci.yml b/.github/workflows/shorebird_ci.yml new file mode 100644 index 0000000000000..a1a81b5ef5d66 --- /dev/null +++ b/.github/workflows/shorebird_ci.yml @@ -0,0 +1,55 @@ +name: shorebird_ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + push: + branches: + - shorebird/dev + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + name: ๐Ÿฆ Shorebird Test + + steps: + - name: ๐Ÿ“š Git Checkout + uses: actions/checkout@v4 + with: + # Fetch all branches and tags to ensure that Flutter can determine its version + fetch-depth: 0 + + # TODO(eseidel): shorebird_tests seems to assume flutter is available + # yet it doesn't seem to set it up here? + - name: ๐ŸŽฏ Setup Dart + uses: dart-lang/setup-dart@v1 + + - uses: actions/setup-java@v4 + with: + distribution: "zulu" + java-version: "17" + + - name: ๐Ÿฆ Run Flutter Tools Tests + # TODO(eseidel): Find a nice way to run this on windows. + if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' }} + run: ../../bin/flutter test test/general.shard + working-directory: packages/flutter_tools + + - name: ๐Ÿฆ Run Shorebird Tests + # TODO(felangel): These tests have a dependency on pkg:flutter_flavorizr which + # requires XCode -- therefore they don't work on Windows. + if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' }} + run: dart test + working-directory: packages/shorebird_tests + env: + # Enables streaming subprocess output for debugging timeouts. + VERBOSE: "1" diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9ce38b8995d..d9a6a608313bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,61 @@ More information and tips: docs/releases/Hotfix-Documentation-Best-Practices.md --> +## Flutter 3.38 Changes + +### [3.38.7](https://github.com/flutter/flutter/releases/tag/3.38.7) + +- [flutter/179857](https://github.com/flutter/flutter/issues/179857) - `flutter run -d all` crashes if multiple devices are available. + +### [3.38.6](https://github.com/flutter/flutter/releases/tag/3.38.6) + +- [flutter/179139](https://github.com/flutter/flutter/issues/179139) - `flutter widget-preview start` creates new cached build artifacts on each run, resulting in increasing disk usage after each run. +- [flutter/178896](https://github.com/flutter/flutter/issues/178896) - Apps crash during launch on Windows when run from paths containing non-ASCII characters. +- [flutter/176943](https://github.com/flutter/flutter/issues/176943) - Configuration changes to run tests on macOS 15 or 15.7.2 for Flutter's CI. +- [flutter/179914](https://github.com/flutter/flutter/issues/179914) - Flutter Android apps that upgrade to AGP 9.0.0 require migration steps. +- [flutter/175099](https://github.com/flutter/flutter/issues/175099) - When WebViews are scrolled on iOS 26, they become unclickable. +- [flutter/175074](https://github.com/flutter/flutter/issues/175074) - When the virtual keyboard is closed on Android web, the area behind it remains blank and the app only draws in the area that used to be above the keyboard. +- [flutter/180381](https://github.com/flutter/flutter/issues/180381) - Apps crash on Android when enabling accessibility, hiding a platform view, and pulling out the top curtain. + +### [3.38.5](https://github.com/flutter/flutter/releases/tag/3.38.5) + +- [flutter/179700](https://github.com/flutter/flutter/issues/179700) Update Dart to 3.10.4. + +### [3.38.4](https://github.com/flutter/flutter/releases/tag/3.38.4) + +- [flutter/178547](https://github.com/flutter/flutter/issues/178547) Rendering issues in the Linux desktop embedder when using Skia. +- [flutter/178529](https://github.com/flutter/flutter/issues/178529) AppLocalizations getting deleted when running debug web +- [flutter/178660](https://github.com/flutter/flutter/issues/178660) `flutter widget-preview start` can crash if `.dart_tool/widget_preview_scaffold/.dart_tool` doesn't exist on subsequent runs. +- [flutter/175227](https://github.com/flutter/flutter/issues/175227) Flutter Web applications launched in Chrome show a warning related to --no-sandbox. +- [flutter/179155](https://github.com/flutter/flutter/issues/179155) `flutter widget-preview start` crashes if a file named `pubspec.yaml` is modified outside the root of the previewed project. +- [flutter/156692](https://github.com/flutter/flutter/issues/156692) `flutter attach` can crash if the target application disconnects unexpectedly. +- [flutter/179008](https://github.com/flutter/flutter/issues/179008) `flutter pub get` could be spawned multiple times on MacOS when `pubspec.yaml`s outside of the project were modified after a `flutter pub get` in the root project. +- [flutter/178715](https://github.com/flutter/flutter/issues/178715) Running flutter test on Linux/MacOS for Android projects with build hooks fails without the desktop native tooling installed. + +### [3.38.3](https://github.com/flutter/flutter/releases/tag/3.38.3) + +- [flutter/178772](https://github.com/flutter/flutter/issues/178772) Flutter engine reports a different version than the framework. +- [flutter/178804](https://github.com/flutter/flutter/issues/178804) Bump Dart version to [3.10.1](https://github.com/dart-lang/sdk/blob/3.10.1/CHANGELOG.md#3101). + +### [3.38.2](https://github.com/flutter/flutter/releases/tag/3.38.2) + +- [flutter/178472](https://github.com/flutter/flutter/issues/178472) Widget preview command can crash on exit if in the middle of analyzing changes to a Dart file. +- [flutter/178452](https://github.com/flutter/flutter/issues/178452) Flutter fails to build on iOS with error message: "Improperly formatted define flag" in add-to-app scenarios. +- [flutter/178486](https://github.com/flutter/flutter/issues/178486) When running flutter widget-preview start with Flutter Web disabled, an exception is thrown and the widget previewer fails to start. +- [flutter/178317](https://github.com/flutter/flutter/issues/178317) Running flutter pub get can crash the widget previewer when plugin dependencies are added or updated. +- [flutter/178318](https://github.com/flutter/flutter/issues/178318) Certain flutter crash scenarios can result in multiple crash reports being submitted for a single process crash. +- [flutter/176399](https://github.com/flutter/flutter/issues/176399) Visual Studio 2026 is not supported when compiling Windows desktop applications. +- [flutter/175058](https://github.com/flutter/flutter/issues/175058) The widget previewer fails to start if flutter pub get has not been run in the target project. +- [flutter/178421](https://github.com/flutter/flutter/issues/178421) When debugging from an IDE with a physical iOS 26 device, IDE installs an app but hangs on a white screen during launching. + +### [3.38.1](https://github.com/flutter/flutter/releases/tag/3.38.1) + +- [flutter/178400](https://github.com/flutter/flutter/issues/178400) Adds support for Dart 3.10 stable. + +### [3.38.0](https://github.com/flutter/flutter/releases/tag/3.38.0) + +Learn about what's new in this release in [the blog post](https://blog.flutter.dev/whats-new-in-flutter-3-38-3f7b258f7228), and check out the [CHANGELOG](https://docs.flutter.dev/release/release-notes/release-notes-3.38.0) for a detailed list of all the new changes. + ## Flutter 3.35 Changes ### [3.35.5](https://github.com/flutter/flutter/releases/tag/3.35.5) diff --git a/DEPS b/DEPS index c27fe356deff1..f9ca7b8736e8d 100644 --- a/DEPS +++ b/DEPS @@ -15,6 +15,10 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', + "dart_sdk_revision": "2b8f13770fa72a8ef56b1406f873ee900c45ec2e", + "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", + "updater_git": "https://github.com/shorebirdtech/updater.git", + "updater_rev": "8691c8f60e69f8eb1f35361f4a22e8c9a7fdf93c", # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -56,15 +60,15 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': '94670bffc27d8233f94a77199e2803a5c4c8ff78', + 'dart_revision': '2da4111d8d0cbf2a83c0662251508f017000da8a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py - 'dart_ai_rev': '59db320ee39a1ae5f6e2830be851e52bb7263ce1', + 'dart_ai_rev': '0a85ddf4f75cee6e3abe07cecdffae69bbdbc793', 'dart_binaryen_rev': '1d2e23d5e55788091a51420ba3a9889d4efe7509', 'dart_boringssl_rev': '706742e482d89214f13a642ccfcdad596a24a32f', 'dart_core_rev': '5c3e2c38df268be2347f3aad30ced0147dd012bb', - 'dart_devtools_rev': '0327830448901920f739259364c3f2f624df5a03', + 'dart_devtools_rev': '9360cc98ac03a6e50a9f56213fb7f45e62f55fcf', 'dart_ecosystem_rev': '96ee86147a5f4c70aed64262e1521b745936cdb1', 'dart_http_rev': '2c53fa3c558ec5d1dd9fce4360d435113dba11e5', 'dart_i18n_rev': '34d1832b7e65d9aef1f7f6a82c22f6e53476191c', @@ -294,7 +298,7 @@ deps = { # Var('flutter_git') + '/third_party/protobuf-gn' + '@' + Var('dart_protobuf_gn_rev'), 'engine/src/flutter/third_party/dart': - Var('dart_git') + '/sdk.git' + '@' + Var('dart_revision'), + Var('dart_sdk_git') + '@' + Var('dart_sdk_revision'), # WARNING: Unused Dart dependencies in the list below till "WARNING:" marker are removed automatically - see create_updated_flutter_deps.py. @@ -302,7 +306,7 @@ deps = { Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@1d2e23d5e55788091a51420ba3a9889d4efe7509', 'engine/src/flutter/third_party/dart/third_party/devtools': - {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:0327830448901920f739259364c3f2f624df5a03'}]}, + {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:9360cc98ac03a6e50a9f56213fb7f45e62f55fcf'}]}, 'engine/src/flutter/third_party/dart/third_party/pkg/ai': Var('dart_git') + '/ai.git' + '@' + Var('dart_ai_rev'), @@ -314,7 +318,7 @@ deps = { Var('dart_git') + '/dart_style.git@ca019b0498692ad78f5f0f0f6208a1258e17fc90', 'engine/src/flutter/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@ec2a4feee51961e9fbdd2bd94060cc8fc994c47e', + Var('dart_git') + '/dartdoc.git@98d03ad2cc341d1fb053e0addfc96ba35301976b', 'engine/src/flutter/third_party/dart/third_party/pkg/ecosystem': Var('dart_git') + '/ecosystem.git' + '@' + Var('dart_ecosystem_rev'), @@ -488,6 +492,9 @@ deps = { 'engine/src/flutter/third_party/ocmock': Var('flutter_git') + '/third_party/ocmock' + '@' + Var('ocmock_rev'), + 'engine/src/flutter/third_party/updater': + Var('updater_git') + '@' + Var('updater_rev'), + 'engine/src/flutter/third_party/libjpeg-turbo/src': Var('flutter_git') + '/third_party/libjpeg-turbo' + '@' + '0fb821f3b2e570b2783a94ccd9a2fb1f4916ae9f', diff --git a/bin/internal/content_aware_hash.ps1 b/bin/internal/content_aware_hash.ps1 index a8439ae879190..275af26df3648 100644 --- a/bin/internal/content_aware_hash.ps1 +++ b/bin/internal/content_aware_hash.ps1 @@ -44,7 +44,7 @@ if (($currentBranch -ne "main") -and ($currentBranch -ne "master") -and ($currentBranch -ne "stable") -and ($currentBranch -ne "beta") -and - (-not (($currentBranch -eq "HEAD") -and (-not [string]::IsNullOrEmpty($env:LUCI_CI)))) -and + (-not (($currentBranch -eq "HEAD") -and (-not [string]::IsNullOrEmpty($env:LUCI_CONTEXT)))) -and (-not $currentBranch.StartsWith("gh-readonly-queue/master/pr-")) -and (-not ($currentBranch -like "flutter-*-candidate.*")) -and (-not $isShallow)) { diff --git a/bin/internal/content_aware_hash.sh b/bin/internal/content_aware_hash.sh index b5e0945c63961..b440b5c133de0 100755 --- a/bin/internal/content_aware_hash.sh +++ b/bin/internal/content_aware_hash.sh @@ -44,7 +44,7 @@ if [[ "$CURRENT_BRANCH" != "main" && \ "$CURRENT_BRANCH" != "beta" && \ "$CURRENT_BRANCH" != "gh-readonly-queue/master/pr-"* && \ "$CURRENT_BRANCH" != "flutter-"*"-candidate."* && \ - ! ( "$CURRENT_BRANCH" == "HEAD" && -n "$LUCI_CI" ) && \ + ! ( "$CURRENT_BRANCH" == "HEAD" && -n "$LUCI_CONTEXT" ) && \ ! -f "$FLUTTER_ROOT/.git/shallow" ]]; then # This is a development branch. Find the merge-base. diff --git a/bin/internal/engine.version b/bin/internal/engine.version new file mode 100644 index 0000000000000..888d159660336 --- /dev/null +++ b/bin/internal/engine.version @@ -0,0 +1 @@ +104f3eb18abaeb8e3551ec7d6ecedaac525f3d02 \ No newline at end of file diff --git a/bin/internal/release-candidate-branch.version b/bin/internal/release-candidate-branch.version new file mode 100644 index 0000000000000..41c657be68b80 --- /dev/null +++ b/bin/internal/release-candidate-branch.version @@ -0,0 +1 @@ +flutter-3.38-candidate.0 diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 11bfbee4fb6cd..ce9892a035e49 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -42,7 +42,7 @@ if ((Test-Path $engineStamp) -and ($engineVersion -eq (Get-Content $engineStamp) $dartSdkBaseUrl = $Env:FLUTTER_STORAGE_BASE_URL if (-not $dartSdkBaseUrl) { - $dartSdkBaseUrl = "https://storage.googleapis.com" + $dartSdkBaseUrl = "https://download.shorebird.dev" } if ($engineRealm) { $dartSdkBaseUrl = "$dartSdkBaseUrl/$engineRealm" diff --git a/bin/internal/update_dart_sdk.sh b/bin/internal/update_dart_sdk.sh index 9ab6151021a8b..6e3617a328342 100755 --- a/bin/internal/update_dart_sdk.sh +++ b/bin/internal/update_dart_sdk.sh @@ -123,7 +123,7 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t FIND=find fi - DART_SDK_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.googleapis.com}${ENGINE_REALM:+/$ENGINE_REALM}" + DART_SDK_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://download.shorebird.dev}${ENGINE_REALM:+/$ENGINE_REALM}" DART_SDK_URL="$DART_SDK_BASE_URL/flutter_infra_release/flutter/$ENGINE_VERSION/$DART_ZIP_NAME" # if the sdk path exists, copy it to a temporary location diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index c69b34b7d708c..014faff628fb8 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -121,7 +121,7 @@ function generate_docs() { # Install and activate dartdoc. # When updating to a new dartdoc version, please also update # `dartdoc_options.yaml` to include newly introduced error and warning types. - "$DART" pub global activate dartdoc 8.3.3 + "$DART" pub global activate dartdoc 9.0.0 # Build and install the snippets tool, which resides in # the dev/docs/snippets directory. diff --git a/dev/bots/post_process_docs.dart b/dev/bots/post_process_docs.dart index 673ae67c1778b..e25e7b1238884 100644 --- a/dev/bots/post_process_docs.dart +++ b/dev/bots/post_process_docs.dart @@ -38,7 +38,7 @@ Future postProcess() async { await runProcessWithValidations([ 'curl', '-L', - 'https://storage.googleapis.com/flutter_infra_release/flutter/$revision/api_docs.zip', + 'https://download.shorebird.dev/flutter_infra_release/flutter/$revision/api_docs.zip', '--output', zipDestination, '--fail', diff --git a/dev/bots/unpublish_package.dart b/dev/bots/unpublish_package.dart index 88c9a6acc552b..5f394bf3802df 100644 --- a/dev/bots/unpublish_package.dart +++ b/dev/bots/unpublish_package.dart @@ -23,7 +23,7 @@ import 'package:process/process.dart'; const String gsBase = 'gs://flutter_infra_release'; const String releaseFolder = '/releases'; const String gsReleaseFolder = '$gsBase$releaseFolder'; -const String baseUrl = 'https://storage.googleapis.com/flutter_infra_release'; +const String baseUrl = 'https://download.shorebird.dev/flutter_infra_release'; /// Exception class for when a process fails to run, so we can catch /// it and provide something more readable than a stack trace. diff --git a/dev/devicelab/bin/tasks/android_java17_dependency_smoke_tests.dart b/dev/devicelab/bin/tasks/android_java17_dependency_smoke_tests.dart index bebc06c0e43a2..cf7bed506f20b 100644 --- a/dev/devicelab/bin/tasks/android_java17_dependency_smoke_tests.dart +++ b/dev/devicelab/bin/tasks/android_java17_dependency_smoke_tests.dart @@ -21,12 +21,12 @@ List versionTuples = [ // Template VersionTuple(agpVersion: '8.9.1', gradleVersion: '8.12', kotlinVersion: '2.1.0'), // Max known - VersionTuple(agpVersion: '8.10.0', gradleVersion: '9.1.0', kotlinVersion: '2.2.0'), + VersionTuple(agpVersion: '8.13.0', gradleVersion: '9.1.0', kotlinVersion: '2.2.0'), /* Others */ VersionTuple(agpVersion: '8.4.0', gradleVersion: '8.6', kotlinVersion: '1.8.22'), VersionTuple(agpVersion: '8.6.0', gradleVersion: '8.7', kotlinVersion: '1.8.22'), VersionTuple(agpVersion: '8.7.0', gradleVersion: '8.9', kotlinVersion: '2.1.0'), - VersionTuple(agpVersion: '8.10.0', gradleVersion: '8.11.1', kotlinVersion: '2.2.0'), + VersionTuple(agpVersion: '8.11.1', gradleVersion: '8.14', kotlinVersion: '2.2.20'), ]; // Max length is 7 entries until this test is split See https://github.com/flutter/flutter/issues/167495. Future main() async { diff --git a/dev/integration_tests/android_semantics_testing/android/buildscript-gradle.lockfile b/dev/integration_tests/android_semantics_testing/android/buildscript-gradle.lockfile index 885a1238a8e7c..0675f01f295f3 100644 --- a/dev/integration_tests/android_semantics_testing/android/buildscript-gradle.lockfile +++ b/dev/integration_tests/android_semantics_testing/android/buildscript-gradle.lockfile @@ -1,68 +1,67 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -androidx.databinding:databinding-common:8.7.0=classpath -androidx.databinding:databinding-compiler-common:8.7.0=classpath -com.android.application:com.android.application.gradle.plugin:8.7.0=classpath -com.android.databinding:baseLibrary:8.7.0=classpath -com.android.tools.analytics-library:crash:31.7.0=classpath -com.android.tools.analytics-library:protos:31.7.0=classpath -com.android.tools.analytics-library:shared:31.7.0=classpath -com.android.tools.analytics-library:tracker:31.7.0=classpath +androidx.databinding:databinding-common:8.11.1=classpath +androidx.databinding:databinding-compiler-common:8.11.1=classpath +com.android.application:com.android.application.gradle.plugin:8.11.1=classpath +com.android.databinding:baseLibrary:8.11.1=classpath +com.android.tools.analytics-library:crash:31.11.1=classpath +com.android.tools.analytics-library:protos:31.11.1=classpath +com.android.tools.analytics-library:shared:31.11.1=classpath +com.android.tools.analytics-library:tracker:31.11.1=classpath com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath -com.android.tools.build:aapt2-proto:8.7.0-12006047=classpath -com.android.tools.build:aaptcompiler:8.7.0=classpath -com.android.tools.build:apksig:8.7.0=classpath -com.android.tools.build:apkzlib:8.7.0=classpath -com.android.tools.build:builder-model:8.7.0=classpath -com.android.tools.build:builder-test-api:8.7.0=classpath -com.android.tools.build:builder:8.7.0=classpath -com.android.tools.build:bundletool:1.17.1=classpath -com.android.tools.build:gradle-api:8.7.0=classpath -com.android.tools.build:gradle-settings-api:8.7.0=classpath -com.android.tools.build:gradle:8.7.0=classpath -com.android.tools.build:manifest-merger:31.7.0=classpath +com.android.tools.build:aapt2-proto:8.11.1-12782657=classpath +com.android.tools.build:aaptcompiler:8.11.1=classpath +com.android.tools.build:apksig:8.11.1=classpath +com.android.tools.build:apkzlib:8.11.1=classpath +com.android.tools.build:builder-model:8.11.1=classpath +com.android.tools.build:builder-test-api:8.11.1=classpath +com.android.tools.build:builder:8.11.1=classpath +com.android.tools.build:bundletool:1.18.1=classpath +com.android.tools.build:gradle-api:8.11.1=classpath +com.android.tools.build:gradle-settings-api:8.11.1=classpath +com.android.tools.build:gradle:8.11.1=classpath +com.android.tools.build:manifest-merger:31.11.1=classpath com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath -com.android.tools.ddms:ddmlib:31.7.0=classpath -com.android.tools.layoutlib:layoutlib-api:31.7.0=classpath -com.android.tools.lint:lint-model:31.7.0=classpath -com.android.tools.lint:lint-typedef-remover:31.7.0=classpath -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=classpath -com.android.tools:annotations:31.7.0=classpath -com.android.tools:common:31.7.0=classpath -com.android.tools:dvlib:31.7.0=classpath -com.android.tools:repository:31.7.0=classpath -com.android.tools:sdk-common:31.7.0=classpath -com.android.tools:sdklib:31.7.0=classpath -com.android:signflinger:8.7.0=classpath -com.android:zipflinger:8.7.0=classpath +com.android.tools.ddms:ddmlib:31.11.1=classpath +com.android.tools.layoutlib:layoutlib-api:31.11.1=classpath +com.android.tools.lint:lint-model:31.11.1=classpath +com.android.tools.lint:lint-typedef-remover:31.11.1=classpath +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=classpath +com.android.tools:annotations:31.11.1=classpath +com.android.tools:common:31.11.1=classpath +com.android.tools:dvlib:31.11.1=classpath +com.android.tools:repository:31.11.1=classpath +com.android.tools:sdk-common:31.11.1=classpath +com.android.tools:sdklib:31.11.1=classpath +com.android:signflinger:8.11.1=classpath +com.android:zipflinger:8.11.1=classpath com.google.android:annotations:4.1.1.4=classpath -com.google.api.grpc:proto-google-common-protos:2.17.0=classpath +com.google.api.grpc:proto-google-common-protos:2.48.0=classpath com.google.auto.value:auto-value-annotations:1.6.2=classpath com.google.code.findbugs:jsr305:3.0.2=classpath -com.google.code.gson:gson:2.10.1=classpath +com.google.code.gson:gson:2.11.0=classpath com.google.crypto.tink:tink:1.7.0=classpath com.google.dagger:dagger:2.28.3=classpath -com.google.errorprone:error_prone_annotations:2.18.0=classpath +com.google.errorprone:error_prone_annotations:2.30.0=classpath com.google.flatbuffers:flatbuffers-java:1.12.0=classpath -com.google.guava:failureaccess:1.0.1=classpath -com.google.guava:guava:32.0.1-jre=classpath +com.google.guava:failureaccess:1.0.2=classpath +com.google.guava:guava:33.3.1-jre=classpath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath -com.google.j2objc:j2objc-annotations:2.8=classpath +com.google.j2objc:j2objc-annotations:3.0.0=classpath com.google.jimfs:jimfs:1.1=classpath -com.google.protobuf:protobuf-java-util:3.22.3=classpath -com.google.protobuf:protobuf-java:3.22.3=classpath -com.google.testing.platform:core-proto:0.0.9-alpha02=classpath +com.google.protobuf:protobuf-java-util:3.25.5=classpath +com.google.protobuf:protobuf-java:3.25.5=classpath +com.google.testing.platform:core-proto:0.0.9-alpha03=classpath com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath com.squareup:javapoet:1.10.0=classpath com.squareup:javawriter:2.5.0=classpath @@ -70,27 +69,29 @@ com.sun.activation:javax.activation:1.2.0=classpath com.sun.istack:istack-commons-runtime:3.0.8=classpath com.sun.xml.fastinfoset:FastInfoset:1.2.16=classpath commons-codec:commons-codec:1.11=classpath -commons-io:commons-io:2.13.0=classpath +commons-io:commons-io:2.16.1=classpath commons-logging:commons-logging:1.2=classpath -io.grpc:grpc-api:1.57.0=classpath -io.grpc:grpc-context:1.57.0=classpath -io.grpc:grpc-core:1.57.0=classpath -io.grpc:grpc-netty:1.57.0=classpath -io.grpc:grpc-protobuf-lite:1.57.0=classpath -io.grpc:grpc-protobuf:1.57.0=classpath -io.grpc:grpc-stub:1.57.0=classpath -io.netty:netty-buffer:4.1.93.Final=classpath -io.netty:netty-codec-http2:4.1.93.Final=classpath -io.netty:netty-codec-http:4.1.93.Final=classpath -io.netty:netty-codec-socks:4.1.93.Final=classpath -io.netty:netty-codec:4.1.93.Final=classpath -io.netty:netty-common:4.1.93.Final=classpath -io.netty:netty-handler-proxy:4.1.93.Final=classpath -io.netty:netty-handler:4.1.93.Final=classpath -io.netty:netty-resolver:4.1.93.Final=classpath -io.netty:netty-transport-native-unix-common:4.1.93.Final=classpath -io.netty:netty-transport:4.1.93.Final=classpath -io.perfmark:perfmark-api:0.26.0=classpath +io.grpc:grpc-api:1.69.1=classpath +io.grpc:grpc-context:1.69.1=classpath +io.grpc:grpc-core:1.69.1=classpath +io.grpc:grpc-inprocess:1.69.1=classpath +io.grpc:grpc-netty:1.69.1=classpath +io.grpc:grpc-protobuf-lite:1.69.1=classpath +io.grpc:grpc-protobuf:1.69.1=classpath +io.grpc:grpc-stub:1.69.1=classpath +io.grpc:grpc-util:1.69.1=classpath +io.netty:netty-buffer:4.1.110.Final=classpath +io.netty:netty-codec-http2:4.1.110.Final=classpath +io.netty:netty-codec-http:4.1.110.Final=classpath +io.netty:netty-codec-socks:4.1.110.Final=classpath +io.netty:netty-codec:4.1.110.Final=classpath +io.netty:netty-common:4.1.110.Final=classpath +io.netty:netty-handler-proxy:4.1.110.Final=classpath +io.netty:netty-handler:4.1.110.Final=classpath +io.netty:netty-resolver:4.1.110.Final=classpath +io.netty:netty-transport-native-unix-common:4.1.110.Final=classpath +io.netty:netty-transport:4.1.110.Final=classpath +io.perfmark:perfmark-api:0.27.0=classpath jakarta.activation:jakarta.activation-api:1.2.1=classpath jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath javax.annotation:javax.annotation-api:1.3.2=classpath @@ -104,50 +105,51 @@ org.apache.httpcomponents:httpclient:4.5.14=classpath org.apache.httpcomponents:httpcore:4.4.16=classpath org.apache.httpcomponents:httpmime:4.5.6=classpath org.bitbucket.b_c:jose4j:0.9.5=classpath -org.bouncycastle:bcpkix-jdk18on:1.77=classpath -org.bouncycastle:bcprov-jdk18on:1.77=classpath -org.bouncycastle:bcutil-jdk18on:1.77=classpath -org.checkerframework:checker-qual:3.33.0=classpath -org.codehaus.mojo:animal-sniffer-annotations:1.23=classpath +org.bouncycastle:bcpkix-jdk18on:1.79=classpath +org.bouncycastle:bcprov-jdk18on:1.79=classpath +org.bouncycastle:bcutil-jdk18on:1.79=classpath +org.checkerframework:checker-qual:3.43.0=classpath +org.codehaus.mojo:animal-sniffer-annotations:1.24=classpath org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath org.glassfish.jaxb:txw2:2.3.2=classpath org.jdom:jdom2:2.0.6=classpath -org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath -org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-statistics:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-tools-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-compiler-runner:2.1.0=classpath -org.jetbrains.kotlin:kotlin-daemon-client:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.1.0=classpath -org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-native-utils:2.1.0=classpath -org.jetbrains.kotlin:kotlin-reflect:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=classpath -org.jetbrains.kotlin:kotlin-tooling-core:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-io:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib-metadata:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib:2.1.0=classpath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath +org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.2.20=classpath +org.jetbrains.kotlin:abi-tools-api:2.2.20=classpath +org.jetbrains.kotlin:fus-statistics-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-statistics:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-tools-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-compiler-runner:2.2.20=classpath +org.jetbrains.kotlin:kotlin-daemon-client:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.2.20=classpath +org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-native-utils:2.2.20=classpath +org.jetbrains.kotlin:kotlin-reflect:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=classpath +org.jetbrains.kotlin:kotlin-tooling-core:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-io:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib-metadata:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib:2.2.20=classpath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0=classpath org.jetbrains:annotations:23.0.0=classpath org.jvnet.staxex:stax-ex:1.8.1=classpath -org.ow2.asm:asm-analysis:9.6=classpath -org.ow2.asm:asm-commons:9.6=classpath -org.ow2.asm:asm-tree:9.6=classpath -org.ow2.asm:asm-util:9.6=classpath -org.ow2.asm:asm:9.6=classpath +org.ow2.asm:asm-analysis:9.7.1=classpath +org.ow2.asm:asm-commons:9.7.1=classpath +org.ow2.asm:asm-tree:9.7.1=classpath +org.ow2.asm:asm-util:9.7.1=classpath +org.ow2.asm:asm:9.7.1=classpath org.slf4j:slf4j-api:1.7.30=classpath -org.tensorflow:tensorflow-lite-metadata:0.1.0-rc2=classpath +org.tensorflow:tensorflow-lite-metadata:0.2.0=classpath empty= diff --git a/dev/integration_tests/android_semantics_testing/android/gradle/wrapper/gradle-wrapper.properties b/dev/integration_tests/android_semantics_testing/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0a835..e4ef43fb98df4 100644 --- a/dev/integration_tests/android_semantics_testing/android/gradle/wrapper/gradle-wrapper.properties +++ b/dev/integration_tests/android_semantics_testing/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/dev/integration_tests/android_semantics_testing/android/project-app.lockfile b/dev/integration_tests/android_semantics_testing/android/project-app.lockfile index 5f3d654dc1372..7ba38e47df1f3 100644 --- a/dev/integration_tests/android_semantics_testing/android/project-app.lockfile +++ b/dev/integration_tests/android_semantics_testing/android/project-app.lockfile @@ -52,8 +52,9 @@ com.android.tools.build:builder:4.1.3=lintClassPath com.android.tools.build:gradle-api:4.1.3=lintClassPath com.android.tools.build:manifest-merger:27.1.3=lintClassPath com.android.tools.ddms:ddmlib:27.1.3=lintClassPath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.external.com-intellij:intellij-core:27.1.3=lintClassPath com.android.tools.external.com-intellij:kotlin-compiler:27.1.3=lintClassPath com.android.tools.external.org-jetbrains:uast:27.1.3=lintClassPath @@ -64,33 +65,36 @@ com.android.tools.lint:lint-gradle-api:27.1.3=lintClassPath com.android.tools.lint:lint-gradle:27.1.3=lintClassPath com.android.tools.lint:lint-model:27.1.3=lintClassPath com.android.tools.lint:lint:27.1.3=lintClassPath -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:annotations:27.1.3=lintClassPath -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:common:27.1.3=lintClassPath -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:dvlib:27.1.3=lintClassPath com.android.tools:repository:27.1.3=lintClassPath com.android.tools:sdk-common:27.1.3=lintClassPath @@ -98,31 +102,52 @@ com.android.tools:sdklib:27.1.3=lintClassPath com.android:signflinger:4.1.3=lintClassPath com.android:zipflinger:4.1.3=lintClassPath com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.github.ben-manes.caffeine:caffeine:2.9.3=swiftExportClasspathResolvable +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.code.findbugs:jsr305:2.0.1=debugAndroidTestCompileClasspath -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.code.gson:gson:2.8.5=lintClassPath +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,swiftExportClasspathResolvable com.google.errorprone:error_prone_annotations:2.3.2=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:guava:28.1-android=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.guava:guava:28.1-jre=lintClassPath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.j2objc:j2objc-annotations:1.3=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.jimfs:jimfs:1.1=lintClassPath +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.protobuf:protobuf-java:3.10.0=lintClassPath -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.googlecode.json-simple:json-simple:1.1=lintClassPath com.squareup:javawriter:2.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.squareup:javawriter:2.5.0=lintClassPath @@ -130,31 +155,66 @@ com.sun.activation:javax.activation:1.2.0=lintClassPath com.sun.istack:istack-commons-runtime:3.0.7=lintClassPath com.sun.xml.fastinfoset:FastInfoset:1.2.15=lintClassPath commons-codec:commons-codec:1.10=lintClassPath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control commons-logging:commons-logging:1.2=lintClassPath -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.github.java-diff-utils:java-diff-utils:4.12=kotlinInternalAbiValidation +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.opentelemetry:opentelemetry-api:1.41.0=swiftExportClasspathResolvable +io.opentelemetry:opentelemetry-context:1.41.0=swiftExportClasspathResolvable +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle it.unimi.dsi:fastutil:7.2.0=lintClassPath javax.activation:javax.activation-api:1.2.0=lintClassPath javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.xml.bind:jaxb-api:2.3.1=lintClassPath junit:junit:4.12=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle @@ -165,14 +225,20 @@ org.apache.commons:commons-compress:1.12=lintClassPath org.apache.httpcomponents:httpclient:4.5.6=lintClassPath org.apache.httpcomponents:httpcore:4.4.10=lintClassPath org.apache.httpcomponents:httpmime:4.5.6=lintClassPath +org.bouncycastle:bcpg-jdk18on:1.80=kotlinBouncyCastleConfiguration org.bouncycastle:bcpkix-jdk15on:1.56=lintClassPath +org.bouncycastle:bcpkix-jdk18on:1.80=kotlinBouncyCastleConfiguration org.bouncycastle:bcprov-jdk15on:1.56=lintClassPath +org.bouncycastle:bcprov-jdk18on:1.80=kotlinBouncyCastleConfiguration +org.bouncycastle:bcutil-jdk18on:1.80=kotlinBouncyCastleConfiguration org.checkerframework:checker-compat-qual:2.5.5=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath org.checkerframework:checker-qual:2.8.1=lintClassPath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,swiftExportClasspathResolvable org.codehaus.groovy:groovy-all:2.4.15=lintClassPath org.codehaus.mojo:animal-sniffer-annotations:1.18=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -182,44 +248,64 @@ org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt -org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-build-common:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-api:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-impl:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-compiler-embeddable:2.1.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-compiler-runner:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-client:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-embeddable:2.1.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.1.0=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:abi-tools-api:2.2.20=kotlinInternalAbiValidation +org.jetbrains.kotlin:abi-tools:2.2.20=kotlinInternalAbiValidation +org.jetbrains.kotlin:kotlin-build-tools-api:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-impl:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlin:kotlin-compiler-runner:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-client:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.2.20=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-metadata-jvm:2.2.20=kotlinInternalAbiValidation org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-script-runtime:2.1.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-scripting-common:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.1.0=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-scripting-jvm:2.1.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-script-runtime:2.2.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlin:kotlin-scripting-common:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.2.20=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-scripting-jvm:2.2.20=kotlinBuildToolsApiClasspath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-common:2.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib:2.1.0=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:2.2.20=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlin:swift-export-embeddable:2.2.20=swiftExportClasspathResolvable +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,swiftExportClasspathResolvable +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.3=swiftExportClasspathResolvable +org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.3=swiftExportClasspathResolvable +org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3=swiftExportClasspathResolvable org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,lintClassPath -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,lintClassPath,swiftExportClasspathResolvable +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-analysis:9.1=androidJacocoAnt diff --git a/dev/integration_tests/android_semantics_testing/android/project-integration_test.lockfile b/dev/integration_tests/android_semantics_testing/android/project-integration_test.lockfile index cd203007a27e2..6cc987832852c 100644 --- a/dev/integration_tests/android_semantics_testing/android/project-integration_test.lockfile +++ b/dev/integration_tests/android_semantics_testing/android/project-integration_test.lockfile @@ -51,8 +51,9 @@ com.android.tools.build:builder:4.1.3=lintClassPath com.android.tools.build:gradle-api:4.1.3=lintClassPath com.android.tools.build:manifest-merger:27.1.3=lintClassPath com.android.tools.ddms:ddmlib:27.1.3=lintClassPath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.external.com-intellij:intellij-core:27.1.3=lintClassPath com.android.tools.external.com-intellij:kotlin-compiler:27.1.3=lintClassPath com.android.tools.external.org-jetbrains:uast:27.1.3=lintClassPath @@ -63,33 +64,36 @@ com.android.tools.lint:lint-gradle-api:27.1.3=lintClassPath com.android.tools.lint:lint-gradle:27.1.3=lintClassPath com.android.tools.lint:lint-model:27.1.3=lintClassPath com.android.tools.lint:lint:27.1.3=lintClassPath -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:annotations:27.1.3=lintClassPath -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:common:27.1.3=lintClassPath -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools:dvlib:27.1.3=lintClassPath com.android.tools:repository:27.1.3=lintClassPath com.android.tools:sdk-common:27.1.3=lintClassPath @@ -97,30 +101,50 @@ com.android.tools:sdklib:27.1.3=lintClassPath com.android:signflinger:4.1.3=lintClassPath com.android:zipflinger:4.1.3=lintClassPath com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.code.gson:gson:2.8.5=lintClassPath +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat com.google.errorprone:error_prone_annotations:2.3.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:guava:28.1-android=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:guava:28.1-jre=lintClassPath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.j2objc:j2objc-annotations:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.jimfs:jimfs:1.1=lintClassPath +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.protobuf:protobuf-java:3.10.0=lintClassPath -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.googlecode.json-simple:json-simple:1.1=lintClassPath com.squareup:javawriter:2.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.squareup:javawriter:2.5.0=lintClassPath @@ -128,31 +152,63 @@ com.sun.activation:javax.activation:1.2.0=lintClassPath com.sun.istack:istack-commons-runtime:3.0.7=lintClassPath com.sun.xml.fastinfoset:FastInfoset:1.2.15=lintClassPath commons-codec:commons-codec:1.10=lintClassPath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control commons-logging:commons-logging:1.2=lintClassPath -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle it.unimi.dsi:fastutil:7.2.0=lintClassPath javax.activation:javax.activation-api:1.2.0=lintClassPath javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.xml.bind:jaxb-api:2.3.1=lintClassPath junit:junit:4.12=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -170,10 +226,12 @@ org.bouncycastle:bcpkix-jdk15on:1.56=lintClassPath org.bouncycastle:bcprov-jdk15on:1.56=lintClassPath org.checkerframework:checker-compat-qual:2.5.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.checkerframework:checker-qual:2.8.1=lintClassPath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.codehaus.groovy:groovy-all:2.4.15=lintClassPath org.codehaus.mojo:animal-sniffer-annotations:1.18=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -184,28 +242,42 @@ org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,lintClassPath -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention,lintClassPath +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.mockito:mockito-core:5.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/android_semantics_testing/android/settings.gradle b/dev/integration_tests/android_semantics_testing/android/settings.gradle index f6ccfc7dc8efa..239244ee26d7b 100644 --- a/dev/integration_tests/android_semantics_testing/android/settings.gradle +++ b/dev/integration_tests/android_semantics_testing/android/settings.gradle @@ -34,8 +34,8 @@ buildscript { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.0" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false + id "com.android.application" version "8.11.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" diff --git a/dev/integration_tests/flutter_gallery/android/buildscript-gradle.lockfile b/dev/integration_tests/flutter_gallery/android/buildscript-gradle.lockfile index 885a1238a8e7c..0675f01f295f3 100644 --- a/dev/integration_tests/flutter_gallery/android/buildscript-gradle.lockfile +++ b/dev/integration_tests/flutter_gallery/android/buildscript-gradle.lockfile @@ -1,68 +1,67 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -androidx.databinding:databinding-common:8.7.0=classpath -androidx.databinding:databinding-compiler-common:8.7.0=classpath -com.android.application:com.android.application.gradle.plugin:8.7.0=classpath -com.android.databinding:baseLibrary:8.7.0=classpath -com.android.tools.analytics-library:crash:31.7.0=classpath -com.android.tools.analytics-library:protos:31.7.0=classpath -com.android.tools.analytics-library:shared:31.7.0=classpath -com.android.tools.analytics-library:tracker:31.7.0=classpath +androidx.databinding:databinding-common:8.11.1=classpath +androidx.databinding:databinding-compiler-common:8.11.1=classpath +com.android.application:com.android.application.gradle.plugin:8.11.1=classpath +com.android.databinding:baseLibrary:8.11.1=classpath +com.android.tools.analytics-library:crash:31.11.1=classpath +com.android.tools.analytics-library:protos:31.11.1=classpath +com.android.tools.analytics-library:shared:31.11.1=classpath +com.android.tools.analytics-library:tracker:31.11.1=classpath com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath -com.android.tools.build:aapt2-proto:8.7.0-12006047=classpath -com.android.tools.build:aaptcompiler:8.7.0=classpath -com.android.tools.build:apksig:8.7.0=classpath -com.android.tools.build:apkzlib:8.7.0=classpath -com.android.tools.build:builder-model:8.7.0=classpath -com.android.tools.build:builder-test-api:8.7.0=classpath -com.android.tools.build:builder:8.7.0=classpath -com.android.tools.build:bundletool:1.17.1=classpath -com.android.tools.build:gradle-api:8.7.0=classpath -com.android.tools.build:gradle-settings-api:8.7.0=classpath -com.android.tools.build:gradle:8.7.0=classpath -com.android.tools.build:manifest-merger:31.7.0=classpath +com.android.tools.build:aapt2-proto:8.11.1-12782657=classpath +com.android.tools.build:aaptcompiler:8.11.1=classpath +com.android.tools.build:apksig:8.11.1=classpath +com.android.tools.build:apkzlib:8.11.1=classpath +com.android.tools.build:builder-model:8.11.1=classpath +com.android.tools.build:builder-test-api:8.11.1=classpath +com.android.tools.build:builder:8.11.1=classpath +com.android.tools.build:bundletool:1.18.1=classpath +com.android.tools.build:gradle-api:8.11.1=classpath +com.android.tools.build:gradle-settings-api:8.11.1=classpath +com.android.tools.build:gradle:8.11.1=classpath +com.android.tools.build:manifest-merger:31.11.1=classpath com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath -com.android.tools.ddms:ddmlib:31.7.0=classpath -com.android.tools.layoutlib:layoutlib-api:31.7.0=classpath -com.android.tools.lint:lint-model:31.7.0=classpath -com.android.tools.lint:lint-typedef-remover:31.7.0=classpath -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=classpath -com.android.tools:annotations:31.7.0=classpath -com.android.tools:common:31.7.0=classpath -com.android.tools:dvlib:31.7.0=classpath -com.android.tools:repository:31.7.0=classpath -com.android.tools:sdk-common:31.7.0=classpath -com.android.tools:sdklib:31.7.0=classpath -com.android:signflinger:8.7.0=classpath -com.android:zipflinger:8.7.0=classpath +com.android.tools.ddms:ddmlib:31.11.1=classpath +com.android.tools.layoutlib:layoutlib-api:31.11.1=classpath +com.android.tools.lint:lint-model:31.11.1=classpath +com.android.tools.lint:lint-typedef-remover:31.11.1=classpath +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=classpath +com.android.tools:annotations:31.11.1=classpath +com.android.tools:common:31.11.1=classpath +com.android.tools:dvlib:31.11.1=classpath +com.android.tools:repository:31.11.1=classpath +com.android.tools:sdk-common:31.11.1=classpath +com.android.tools:sdklib:31.11.1=classpath +com.android:signflinger:8.11.1=classpath +com.android:zipflinger:8.11.1=classpath com.google.android:annotations:4.1.1.4=classpath -com.google.api.grpc:proto-google-common-protos:2.17.0=classpath +com.google.api.grpc:proto-google-common-protos:2.48.0=classpath com.google.auto.value:auto-value-annotations:1.6.2=classpath com.google.code.findbugs:jsr305:3.0.2=classpath -com.google.code.gson:gson:2.10.1=classpath +com.google.code.gson:gson:2.11.0=classpath com.google.crypto.tink:tink:1.7.0=classpath com.google.dagger:dagger:2.28.3=classpath -com.google.errorprone:error_prone_annotations:2.18.0=classpath +com.google.errorprone:error_prone_annotations:2.30.0=classpath com.google.flatbuffers:flatbuffers-java:1.12.0=classpath -com.google.guava:failureaccess:1.0.1=classpath -com.google.guava:guava:32.0.1-jre=classpath +com.google.guava:failureaccess:1.0.2=classpath +com.google.guava:guava:33.3.1-jre=classpath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath -com.google.j2objc:j2objc-annotations:2.8=classpath +com.google.j2objc:j2objc-annotations:3.0.0=classpath com.google.jimfs:jimfs:1.1=classpath -com.google.protobuf:protobuf-java-util:3.22.3=classpath -com.google.protobuf:protobuf-java:3.22.3=classpath -com.google.testing.platform:core-proto:0.0.9-alpha02=classpath +com.google.protobuf:protobuf-java-util:3.25.5=classpath +com.google.protobuf:protobuf-java:3.25.5=classpath +com.google.testing.platform:core-proto:0.0.9-alpha03=classpath com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath com.squareup:javapoet:1.10.0=classpath com.squareup:javawriter:2.5.0=classpath @@ -70,27 +69,29 @@ com.sun.activation:javax.activation:1.2.0=classpath com.sun.istack:istack-commons-runtime:3.0.8=classpath com.sun.xml.fastinfoset:FastInfoset:1.2.16=classpath commons-codec:commons-codec:1.11=classpath -commons-io:commons-io:2.13.0=classpath +commons-io:commons-io:2.16.1=classpath commons-logging:commons-logging:1.2=classpath -io.grpc:grpc-api:1.57.0=classpath -io.grpc:grpc-context:1.57.0=classpath -io.grpc:grpc-core:1.57.0=classpath -io.grpc:grpc-netty:1.57.0=classpath -io.grpc:grpc-protobuf-lite:1.57.0=classpath -io.grpc:grpc-protobuf:1.57.0=classpath -io.grpc:grpc-stub:1.57.0=classpath -io.netty:netty-buffer:4.1.93.Final=classpath -io.netty:netty-codec-http2:4.1.93.Final=classpath -io.netty:netty-codec-http:4.1.93.Final=classpath -io.netty:netty-codec-socks:4.1.93.Final=classpath -io.netty:netty-codec:4.1.93.Final=classpath -io.netty:netty-common:4.1.93.Final=classpath -io.netty:netty-handler-proxy:4.1.93.Final=classpath -io.netty:netty-handler:4.1.93.Final=classpath -io.netty:netty-resolver:4.1.93.Final=classpath -io.netty:netty-transport-native-unix-common:4.1.93.Final=classpath -io.netty:netty-transport:4.1.93.Final=classpath -io.perfmark:perfmark-api:0.26.0=classpath +io.grpc:grpc-api:1.69.1=classpath +io.grpc:grpc-context:1.69.1=classpath +io.grpc:grpc-core:1.69.1=classpath +io.grpc:grpc-inprocess:1.69.1=classpath +io.grpc:grpc-netty:1.69.1=classpath +io.grpc:grpc-protobuf-lite:1.69.1=classpath +io.grpc:grpc-protobuf:1.69.1=classpath +io.grpc:grpc-stub:1.69.1=classpath +io.grpc:grpc-util:1.69.1=classpath +io.netty:netty-buffer:4.1.110.Final=classpath +io.netty:netty-codec-http2:4.1.110.Final=classpath +io.netty:netty-codec-http:4.1.110.Final=classpath +io.netty:netty-codec-socks:4.1.110.Final=classpath +io.netty:netty-codec:4.1.110.Final=classpath +io.netty:netty-common:4.1.110.Final=classpath +io.netty:netty-handler-proxy:4.1.110.Final=classpath +io.netty:netty-handler:4.1.110.Final=classpath +io.netty:netty-resolver:4.1.110.Final=classpath +io.netty:netty-transport-native-unix-common:4.1.110.Final=classpath +io.netty:netty-transport:4.1.110.Final=classpath +io.perfmark:perfmark-api:0.27.0=classpath jakarta.activation:jakarta.activation-api:1.2.1=classpath jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath javax.annotation:javax.annotation-api:1.3.2=classpath @@ -104,50 +105,51 @@ org.apache.httpcomponents:httpclient:4.5.14=classpath org.apache.httpcomponents:httpcore:4.4.16=classpath org.apache.httpcomponents:httpmime:4.5.6=classpath org.bitbucket.b_c:jose4j:0.9.5=classpath -org.bouncycastle:bcpkix-jdk18on:1.77=classpath -org.bouncycastle:bcprov-jdk18on:1.77=classpath -org.bouncycastle:bcutil-jdk18on:1.77=classpath -org.checkerframework:checker-qual:3.33.0=classpath -org.codehaus.mojo:animal-sniffer-annotations:1.23=classpath +org.bouncycastle:bcpkix-jdk18on:1.79=classpath +org.bouncycastle:bcprov-jdk18on:1.79=classpath +org.bouncycastle:bcutil-jdk18on:1.79=classpath +org.checkerframework:checker-qual:3.43.0=classpath +org.codehaus.mojo:animal-sniffer-annotations:1.24=classpath org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath org.glassfish.jaxb:txw2:2.3.2=classpath org.jdom:jdom2:2.0.6=classpath -org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath -org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-statistics:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-tools-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-compiler-runner:2.1.0=classpath -org.jetbrains.kotlin:kotlin-daemon-client:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.1.0=classpath -org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-native-utils:2.1.0=classpath -org.jetbrains.kotlin:kotlin-reflect:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=classpath -org.jetbrains.kotlin:kotlin-tooling-core:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-io:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib-metadata:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib:2.1.0=classpath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath +org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.2.20=classpath +org.jetbrains.kotlin:abi-tools-api:2.2.20=classpath +org.jetbrains.kotlin:fus-statistics-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-statistics:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-tools-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-compiler-runner:2.2.20=classpath +org.jetbrains.kotlin:kotlin-daemon-client:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.2.20=classpath +org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-native-utils:2.2.20=classpath +org.jetbrains.kotlin:kotlin-reflect:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=classpath +org.jetbrains.kotlin:kotlin-tooling-core:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-io:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib-metadata:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib:2.2.20=classpath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0=classpath org.jetbrains:annotations:23.0.0=classpath org.jvnet.staxex:stax-ex:1.8.1=classpath -org.ow2.asm:asm-analysis:9.6=classpath -org.ow2.asm:asm-commons:9.6=classpath -org.ow2.asm:asm-tree:9.6=classpath -org.ow2.asm:asm-util:9.6=classpath -org.ow2.asm:asm:9.6=classpath +org.ow2.asm:asm-analysis:9.7.1=classpath +org.ow2.asm:asm-commons:9.7.1=classpath +org.ow2.asm:asm-tree:9.7.1=classpath +org.ow2.asm:asm-util:9.7.1=classpath +org.ow2.asm:asm:9.7.1=classpath org.slf4j:slf4j-api:1.7.30=classpath -org.tensorflow:tensorflow-lite-metadata:0.1.0-rc2=classpath +org.tensorflow:tensorflow-lite-metadata:0.2.0=classpath empty= diff --git a/dev/integration_tests/flutter_gallery/android/gradle/wrapper/gradle-wrapper.properties b/dev/integration_tests/flutter_gallery/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0a835..e4ef43fb98df4 100644 --- a/dev/integration_tests/flutter_gallery/android/gradle/wrapper/gradle-wrapper.properties +++ b/dev/integration_tests/flutter_gallery/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/dev/integration_tests/flutter_gallery/android/project-app.lockfile b/dev/integration_tests/flutter_gallery/android/project-app.lockfile index 1b261a2ce6757..8624b72f013da 100644 --- a/dev/integration_tests/flutter_gallery/android/project-app.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-app.lockfile @@ -53,105 +53,173 @@ androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompile androidx.window.extensions.core:core:1.0.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.window:window-java:1.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.errorprone:error_prone_annotations:2.28.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:failureaccess:1.0.2=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher com.google.guava:guava:33.3.1-android=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.j2objc:j2objc-annotations:3.0.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.squareup:javawriter:2.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath junit:junit:4.12=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath junit:junit:4.13=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.checkerframework:checker-qual:3.43.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-bom:1.8.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib:1.9.24=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath empty=androidApis,androidJdkImage,androidTestUtil,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAnnotationProcessorClasspath,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,debugWearBundling,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileReverseMetadataValues,profileUnitTestAnnotationProcessorClasspath,profileWearBundling,releaseAnnotationProcessorClasspath,releaseReverseMetadataValues,releaseUnitTestAnnotationProcessorClasspath,releaseWearBundling diff --git a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile index 005d2033a2dba..e3b5f6c5360bf 100644 --- a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile @@ -38,77 +38,133 @@ androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroid androidx.window.extensions.core:core:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.window:window-java:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat com.google.errorprone:error_prone_annotations:2.3.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:guava:28.1-android=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.j2objc:j2objc-annotations:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.squareup:javawriter:2.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath junit:junit:4.12=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.bytebuddy:byte-buddy-agent:1.14.10=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -117,9 +173,11 @@ net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-devi net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.checkerframework:checker-compat-qual:2.5.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.codehaus.mojo:animal-sniffer-annotations:1.18=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -127,23 +185,37 @@ org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.mockito:mockito-core:5.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:9.1=androidJacocoAnt diff --git a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile b/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile index 92b094af0a3a0..cd40b47db4242 100644 --- a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile @@ -40,82 +40,137 @@ androidx.window.extensions.core:core:1.0.0=debugAndroidTestRuntimeClasspath,debu androidx.window:window-java:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.almworks.sqlite4java:sqlite4java:1.0.392=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.auto.value:auto-value-annotations:1.11.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core com.google.errorprone:error_prone_annotation:2.38.0=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.errorprone:error_prone_annotations:2.36.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:failureaccess:1.0.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:guava:33.4.8-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:listenablefuture:1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.j2objc:j2objc-annotations:3.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.testparameterinjector:test-parameter-injector:1.18=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath com.ibm.icu:icu4j:77.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -javax.inject:javax.inject:1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.bytebuddy:byte-buddy-agent:1.17.6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.bytebuddy:byte-buddy:1.17.6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -123,35 +178,51 @@ net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-devi net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib org.bouncycastle:bcprov-jdk18on:1.80=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.conscrypt:conscrypt-openjdk-uber:2.5.2=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib:1.9.24=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jspecify:jspecify:1.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.mockito:mockito-core:5.19.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/flutter_gallery/android/project-video_player_android.lockfile b/dev/integration_tests/flutter_gallery/android/project-video_player_android.lockfile index a5a14b66429e6..9ed94f6a00ec5 100644 --- a/dev/integration_tests/flutter_gallery/android/project-video_player_android.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-video_player_android.lockfile @@ -55,59 +55,81 @@ androidx.window.extensions.core:core:1.0.0=debugAndroidTestRuntimeClasspath,debu androidx.window:window-java:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.almworks.sqlite4java:sqlite4java:1.0.392=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.auto.value:auto-value-annotations:1.11.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core com.google.errorprone:error_prone_annotation:2.38.0=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.errorprone:error_prone_annotations:2.36.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:failureaccess:1.0.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath com.google.guava:failureaccess:1.0.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher com.google.guava:guava:33.3.1-android=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:guava:33.4.8-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.j2objc:j2objc-annotations:3.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.testparameterinjector:test-parameter-injector:1.18=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.truth.extensions:truth-java8-extension:1.4.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.truth:truth:1.4.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -116,28 +138,60 @@ com.squareup.okhttp3:mockwebserver:4.12.0=debugUnitTestRuntimeClasspath,profileU com.squareup.okhttp3:okhttp:4.12.0=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okio:okio-jvm:3.6.0=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okio:okio:3.6.0=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -javax.inject:javax.inject:1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.bytebuddy:byte-buddy-agent:1.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.bytebuddy:byte-buddy:1.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -145,9 +199,11 @@ net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-devi net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib org.bouncycastle:bcprov-jdk18on:1.80=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.checkerframework:checker-qual:3.42.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle org.conscrypt:conscrypt-openjdk-uber:2.5.2=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt @@ -155,31 +211,45 @@ org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt org.jetbrains.kotlin:kotlin-bom:1.8.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib-common:1.9.21=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlin:kotlin-stdlib:1.9.21=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jspecify:jspecify:1.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.mockito:mockito-core:5.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.mockito:mockito-inline:5.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/flutter_gallery/android/settings.gradle b/dev/integration_tests/flutter_gallery/android/settings.gradle index f6ccfc7dc8efa..239244ee26d7b 100644 --- a/dev/integration_tests/flutter_gallery/android/settings.gradle +++ b/dev/integration_tests/flutter_gallery/android/settings.gradle @@ -34,8 +34,8 @@ buildscript { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.0" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false + id "com.android.application" version "8.11.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" diff --git a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle index 5368feb7ecde7..66364cdf4a190 100644 --- a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle +++ b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle @@ -7,7 +7,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - def flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://storage.googleapis.com" + def flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://download.shorebird.dev" maven { url = uri("$flutterStorageUrl/download.flutter.io") } diff --git a/dev/integration_tests/pure_android_host_apps/host_app_kotlin_gradle_dsl/settings.gradle.kts b/dev/integration_tests/pure_android_host_apps/host_app_kotlin_gradle_dsl/settings.gradle.kts index f6d75bce11757..da25b49a46f7f 100644 --- a/dev/integration_tests/pure_android_host_apps/host_app_kotlin_gradle_dsl/settings.gradle.kts +++ b/dev/integration_tests/pure_android_host_apps/host_app_kotlin_gradle_dsl/settings.gradle.kts @@ -16,7 +16,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - val flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://storage.googleapis.com" + val flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://download.shorebird.dev" maven("$flutterStorageUrl/download.flutter.io") } } diff --git a/dev/tools/bin/generate_gradle_lockfiles.dart b/dev/tools/bin/generate_gradle_lockfiles.dart index 4cf63b923ca54..77567ac7bc38a 100644 --- a/dev/tools/bin/generate_gradle_lockfiles.dart +++ b/dev/tools/bin/generate_gradle_lockfiles.dart @@ -291,8 +291,8 @@ buildscript { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.0" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false + id "com.android.application" version "8.11.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" @@ -387,8 +387,8 @@ buildscript { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") @@ -399,7 +399,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip '''; Iterable discoverAndroidDirectories(Directory repoRoot) { diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index 1b025d00ea226..03ef7ca88ac54 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -933,7 +933,7 @@ class PlatformDocGenerator { for (final String platform in kPlatformDocs.keys) { final String zipFile = kPlatformDocs[platform]!.zipName; final String url = - 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/$zipFile'; + 'https://download.shorebird.dev/${realm}flutter_infra_release/flutter/$engineRevision/$zipFile'; await _extractDocs(url, platform, kPlatformDocs[platform]!, outputDir); } } diff --git a/dev/tools/test/content_aware_hash_test.dart b/dev/tools/test/content_aware_hash_test.dart index a29fda95a8adf..b31ac9be7c230 100644 --- a/dev/tools/test/content_aware_hash_test.dart +++ b/dev/tools/test/content_aware_hash_test.dart @@ -231,7 +231,7 @@ void main() { ); // Simulate being in a LUCI environment. - environment['LUCI_CI'] = 'true'; + environment['LUCI_CONTEXT'] = 'true'; expect(runContentAwareHash(), processStdout('63a6c6dc494d9a2fc3e78e8505e878d129429246')); }); diff --git a/engine/src/build/config/compiler/BUILD.gn b/engine/src/build/config/compiler/BUILD.gn index 50f1b60eab1a4..87b571ff75e00 100644 --- a/engine/src/build/config/compiler/BUILD.gn +++ b/engine/src/build/config/compiler/BUILD.gn @@ -443,7 +443,10 @@ config("compiler") { # Example PR: https://github.com/dart-lang/native/pull/1615 ldflags += [ "-Wl,--no-undefined", - "-Wl,--exclude-libs,ALL", + + # TODO: Terrible hack, but otherwise libupdater.a symbols can't + # be exported from libflutter.so, even when added to android_exports.lst. + # "-Wl,--exclude-libs,ALL", # Enable identical code folding to reduce size. "-Wl,--icf=all", @@ -646,6 +649,8 @@ config("runtime_library") { ldflags += [ "-Wl,--warn-shared-textrel" ] libs += [ + # Rust requires libunwind. + "unwind", "c", "dl", "m", @@ -660,6 +665,9 @@ config("runtime_library") { } else if (current_cpu == "x86") { current_android_cpu = "i686" } + # libunwind.a is located in the respective android cpu subdirectories. + # The clang version needs to match the version in the lib_dirs line above. + lib_dirs += [ "${android_toolchain_root}/lib/clang/19/lib/linux/${current_android_cpu}/" ] libs += [ "clang_rt.builtins-${current_android_cpu}-android" ] } diff --git a/engine/src/build/toolchain/win/BUILD.gn b/engine/src/build/toolchain/win/BUILD.gn index 45a98b1ecd64b..b5073fb22277b 100644 --- a/engine/src/build/toolchain/win/BUILD.gn +++ b/engine/src/build/toolchain/win/BUILD.gn @@ -204,8 +204,11 @@ template("msvc_toolchain") { expname = "${dllname}.exp" pdbname = "${dllname}.pdb" rspfile = "${dllname}.rsp" + # .def files are used to export symbols from the DLL. This arg will be + # removed by the python tool wrapper if the .def file doesn't exist. + deffile = "${dllname}.def" - link_command = "\"$python_path\" $tool_wrapper_path link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile" + link_command = "\"$python_path\" $tool_wrapper_path link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb /DEF:$deffile @$rspfile" # TODO(brettw) support manifests #manifest_command = "\"$python_path\" $tool_wrapper_path manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:${dllname}.manifest" diff --git a/engine/src/build/toolchain/win/tool_wrapper.py b/engine/src/build/toolchain/win/tool_wrapper.py index b4fc8485ffa17..7866c6122d832 100644 --- a/engine/src/build/toolchain/win/tool_wrapper.py +++ b/engine/src/build/toolchain/win/tool_wrapper.py @@ -121,6 +121,17 @@ def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args): self._UseSeparateMspdbsrv(env, args) if sys.platform == 'win32': args = list(args) # *args is a tuple by default, which is read-only. + + # Remove the /DEF arg if not provided. We would ideally be able to do this + # in build\toolchain\win\BUILD.gn, but there doesn't seem to be a way to + # conditionally add args to the command line based on whether a file exists + # or not, so we do it here instead. + def_arg_prefix = "/DEF:" + for arg in args: + if arg.startswith(def_arg_prefix): + def_file = arg[len(def_arg_prefix):] + if not os.path.exists(def_file): + args.remove(arg) args[0] = args[0].replace('/', '\\') # https://docs.python.org/2/library/subprocess.html: # "On Unix with shell=True [...] if args is a sequence, the first item diff --git a/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 582d3312a843c..7254d55cdae8f 100644 --- a/engine/src/flutter/.ci.yaml +++ b/engine/src/flutter/.ci.yaml @@ -30,7 +30,7 @@ platform_properties: {"dependency": "open_jdk", "version": "version:17"} ] device_type: none - os: Mac-14|Mac-15 + os: Mac-15.5|Mac-15.7 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" @@ -449,7 +449,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14|Mac-15 + - os=Mac-15.5|Mac-15.7 - name: Mac clangd recipe: engine_v2/builder @@ -478,7 +478,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14|Mac-15 + - os=Mac-15.5|Mac-15.7 - cpu=x86 - name: Mac mac_ios_engine_ddm @@ -498,7 +498,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14|Mac-15 + - os=Mac-15.5|Mac-15.7 - cpu=x86 - name: Linux windows_android_aot_engine diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index ec7b55d24f152..348f732c329ed 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -118,6 +118,9 @@ group("flutter") { # path_ops "//flutter/tools/path_ops", + + # Built alongside gen_snapshot arm64 targets. + "$dart_src/runtime/bin:analyze_snapshot", ] if (host_os == "linux" || host_os == "mac") { @@ -127,13 +130,6 @@ group("flutter") { ] } - if (host_os == "linux") { - public_deps += [ - # Built alongside gen_snapshot for 64 bit targets - "$dart_src/runtime/bin:analyze_snapshot", - ] - } - if (full_dart_sdk) { public_deps += [ "//flutter/web_sdk" ] } @@ -213,6 +209,7 @@ group("unittests") { "//flutter/runtime:no_dart_plugin_registrant_unittests", "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", + "//flutter/shell/common/shorebird:shorebird_unittests", "//flutter/shell/geometry:geometry_unittests", "//flutter/shell/platform/embedder:embedder_a11y_unittests", "//flutter/shell/platform/embedder:embedder_proctable_unittests", @@ -344,3 +341,19 @@ if (host_os == "win") { outputs = [ "$root_build_dir/gen_snapshot/gen_snapshot.exe" ] } } + +# A top-level target for analyze_snapshot, modeled after the gen_snapshot +# target above. +if (host_os == "win") { + _analyze_snapshot_target = + "$dart_src/runtime/bin:analyze_snapshot($host_toolchain)" + + copy("analyze_snapshot") { + deps = [ _analyze_snapshot_target ] + + analyze_snapshot_out_dir = + get_label_info(_analyze_snapshot_target, "root_out_dir") + sources = [ "$analyze_snapshot_out_dir/analyze_snapshot.exe" ] + outputs = [ "$root_build_dir/analyze_snapshot/analyze_snapshot.exe" ] + } +} diff --git a/engine/src/flutter/build/archives/BUILD.gn b/engine/src/flutter/build/archives/BUILD.gn index 4f902010d21dc..55700433541db 100644 --- a/engine/src/flutter/build/archives/BUILD.gn +++ b/engine/src/flutter/build/archives/BUILD.gn @@ -45,6 +45,7 @@ generated_file("artifacts_entitlement_config") { if (build_engine_artifacts) { zip_bundle("artifacts") { deps = [ + "$dart_src/runtime/bin:analyze_snapshot", "$dart_src/runtime/bin:gen_snapshot", "//flutter/flutter_frontend_server:frontend_server", "//flutter/impeller/compiler:impellerc", @@ -142,6 +143,10 @@ if (build_engine_artifacts) { if (host_os == "mac") { deps += [ ":artifacts_entitlement_config" ] files += [ + { + source = "$root_out_dir/analyze_snapshot$exe" + destination = "analyze_snapshot$exe" + }, { source = "$target_gen_dir/entitlements.txt" destination = "entitlements.txt" @@ -320,14 +325,25 @@ if (is_mac) { } if (host_os == "win") { + # This rule archives both gen_snapshot *and* analyze_snapshot. The name is + # misleading. We (shorebird) have updated this rule to include + # analyze_snapshot but did not update the name because it is referenced + # elsewhere in the tooling. zip_bundle("archive_win_gen_snapshot") { - deps = [ "//flutter:gen_snapshot" ] + deps = [ + "//flutter:analyze_snapshot", + "//flutter:gen_snapshot", + ] output = "$full_target_platform_name-$flutter_runtime_mode/windows-x64.zip" files = [ { source = "$root_out_dir/gen_snapshot/gen_snapshot.exe" destination = "gen_snapshot.exe" }, + { + source = "$root_out_dir/analyze_snapshot/analyze_snapshot.exe" + destination = "analyze_snapshot.exe" + }, ] } } diff --git a/engine/src/flutter/build/dart/tools/dart_pkg.py b/engine/src/flutter/build/dart/tools/dart_pkg.py index c60e3e02431e4..5b3e0a8b5f3ee 100755 --- a/engine/src/flutter/build/dart/tools/dart_pkg.py +++ b/engine/src/flutter/build/dart/tools/dart_pkg.py @@ -163,7 +163,10 @@ def main(): for source in args.package_sources: relative_source = os.path.relpath(source, common_source_prefix) target = os.path.join(target_dir, relative_source) - copy(source, target) + try: + copy(source, target) + except shutil.SameFileError: + pass # Copy sdk-ext sources into pkg directory sdk_ext_dir = os.path.join(target_dir, 'sdk_ext') @@ -179,7 +182,10 @@ def main(): for source in args.sdk_ext_files: relative_source = os.path.relpath(source, common_source_prefix) target = os.path.join(sdk_ext_dir, relative_source) - copy(source, target) + try: + copy(source, target) + except shutil.SameFileError: + pass # Write stamp file. with open(args.stamp_file, 'w'): diff --git a/engine/src/flutter/build/zip_bundle.gni b/engine/src/flutter/build/zip_bundle.gni index 51e72df0ad854..707ab046d3637 100644 --- a/engine/src/flutter/build/zip_bundle.gni +++ b/engine/src/flutter/build/zip_bundle.gni @@ -55,7 +55,7 @@ template("zip_bundle") { license_path = rebase_path("//flutter/sky/packages/sky_engine/LICENSE", "//flutter") git_url = "https://github.com/flutter/engine/tree/$engine_version" - sky_engine_url = "https://storage.googleapis.com/flutter_infra_release/flutter/$engine_version/sky_engine.zip" + sky_engine_url = "https://download.shorebird.dev/flutter_infra_release/flutter/$engine_version/sky_engine.zip" outputs = [ license_readme ] contents = [ "# $target_name", diff --git a/engine/src/flutter/ci/builders/linux_web_engine_test.json b/engine/src/flutter/ci/builders/linux_web_engine_test.json index 6265590856493..2f129727228a8 100644 --- a/engine/src/flutter/ci/builders/linux_web_engine_test.json +++ b/engine/src/flutter/ci/builders/linux_web_engine_test.json @@ -397,7 +397,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/local_engine.json b/engine/src/flutter/ci/builders/local_engine.json index 51ff9ac8f0329..4aa63478e8e7b 100644 --- a/engine/src/flutter/ci/builders/local_engine.json +++ b/engine/src/flutter/ci/builders/local_engine.json @@ -3,7 +3,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -70,7 +70,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -103,7 +103,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -136,7 +136,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -170,7 +170,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -206,7 +206,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -370,7 +370,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -403,7 +403,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -436,7 +436,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -520,7 +520,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -604,7 +604,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -636,7 +636,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -669,7 +669,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -702,7 +702,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -841,7 +841,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -925,7 +925,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -1063,7 +1063,7 @@ "name": "macos/wasm_release", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15" + "os=Mac-15.5|Mac-15.7" ], "gclient_variables": { "download_android_deps": false, @@ -1093,7 +1093,7 @@ "name": "macos/wasm_debug_unopt", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15" + "os=Mac-15.5|Mac-15.7" ], "gclient_variables": { "download_android_deps": false, diff --git a/engine/src/flutter/ci/builders/mac_android_aot_engine.json b/engine/src/flutter/ci/builders/mac_android_aot_engine.json index 57f61d4c0b156..bec77665a0480 100644 --- a/engine/src/flutter/ci/builders/mac_android_aot_engine.json +++ b/engine/src/flutter/ci/builders/mac_android_aot_engine.json @@ -25,7 +25,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -83,7 +83,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -143,7 +143,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -203,7 +203,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -261,7 +261,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -321,7 +321,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_clang_tidy.json b/engine/src/flutter/ci/builders/mac_clang_tidy.json index 9b18f6a04ca9f..1ad127acec92e 100644 --- a/engine/src/flutter/ci/builders/mac_clang_tidy.json +++ b/engine/src/flutter/ci/builders/mac_clang_tidy.json @@ -3,7 +3,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -74,7 +74,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -129,7 +129,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -184,7 +184,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -239,7 +239,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -294,7 +294,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_host_engine.json b/engine/src/flutter/ci/builders/mac_host_engine.json index 89ebd06bbd965..c79c50e5d6294 100644 --- a/engine/src/flutter/ci/builders/mac_host_engine.json +++ b/engine/src/flutter/ci/builders/mac_host_engine.json @@ -17,7 +17,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -84,7 +84,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -140,7 +140,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -205,7 +205,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -256,7 +256,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -307,7 +307,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -370,7 +370,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -424,7 +424,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -477,7 +477,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -543,7 +543,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -600,7 +600,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -656,7 +656,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -722,7 +722,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -777,7 +777,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -832,7 +832,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -899,7 +899,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -957,7 +957,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -1014,7 +1014,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_ios_engine.json b/engine/src/flutter/ci/builders/mac_ios_engine.json index 3e84fdc4629b2..726cb23488543 100644 --- a/engine/src/flutter/ci/builders/mac_ios_engine.json +++ b/engine/src/flutter/ci/builders/mac_ios_engine.json @@ -14,7 +14,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -61,7 +61,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -110,7 +110,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -157,7 +157,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -204,7 +204,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -251,7 +251,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -300,7 +300,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -351,7 +351,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -449,7 +449,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_unopt.json b/engine/src/flutter/ci/builders/mac_unopt.json index 3d86f83c40f3b..9920a22f07112 100644 --- a/engine/src/flutter/ci/builders/mac_unopt.json +++ b/engine/src/flutter/ci/builders/mac_unopt.json @@ -4,7 +4,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -57,7 +57,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -108,7 +108,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -159,7 +159,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -216,7 +216,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -275,7 +275,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -332,7 +332,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -468,7 +468,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/common/config.gni b/engine/src/flutter/common/config.gni index 318d305bd37fc..35ec1c7e058dc 100644 --- a/engine/src/flutter/common/config.gni +++ b/engine/src/flutter/common/config.gni @@ -67,6 +67,14 @@ if (slimpeller) { feature_defines_list += [ "SLIMPELLER=1" ] } +if (is_android || is_ios || is_linux || is_mac || is_win) { + feature_defines_list += [ "SHOREBIRD_PLATFORM_SUPPORTED=1" ] +} + +if (is_ios) { + feature_defines_list += [ "SHOREBIRD_USE_INTERPRETER=1" ] +} + if (is_ios || is_mac) { flutter_cflags_objc = [ "-Werror=overriding-method-mismatch", diff --git a/engine/src/flutter/fml/string_conversion.cc b/engine/src/flutter/fml/string_conversion.cc index d55577c4e6471..e2f62c0fb117e 100644 --- a/engine/src/flutter/fml/string_conversion.cc +++ b/engine/src/flutter/fml/string_conversion.cc @@ -44,4 +44,9 @@ std::u16string Utf8ToUtf16(const std::string_view string) { return converter.from_bytes(string.data()); } +std::string PathToUtf8(const std::filesystem::path& path) { + const std::u8string path_u8 = path.u8string(); + return std::string(path_u8.begin(), path_u8.end()); +} + } // namespace fml diff --git a/engine/src/flutter/fml/string_conversion.h b/engine/src/flutter/fml/string_conversion.h index eb7d840c3c717..48fb450a577d3 100644 --- a/engine/src/flutter/fml/string_conversion.h +++ b/engine/src/flutter/fml/string_conversion.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_FML_STRING_CONVERSION_H_ #define FLUTTER_FML_STRING_CONVERSION_H_ +#include #include #include @@ -19,6 +20,9 @@ std::string Utf16ToUtf8(const std::u16string_view string); // Returns a UTF-16 encoded equivalent of a UTF-8 encoded input string. std::u16string Utf8ToUtf16(const std::string_view string); +// Returns the pathname encoded in UTF-8. +std::string PathToUtf8(const std::filesystem::path& path); + } // namespace fml #endif // FLUTTER_FML_STRING_CONVERSION_H_ diff --git a/engine/src/flutter/fml/string_conversion_unittests.cc b/engine/src/flutter/fml/string_conversion_unittests.cc index 4d12075709014..2369e4b39e6a9 100644 --- a/engine/src/flutter/fml/string_conversion_unittests.cc +++ b/engine/src/flutter/fml/string_conversion_unittests.cc @@ -33,5 +33,10 @@ TEST(StringConversion, Utf16ToUtf8Unicode) { EXPECT_EQ(Utf16ToUtf8(u"\x2603"), "\xe2\x98\x83"); } +TEST(StringConversion, PathToUtf8) { + EXPECT_EQ(PathToUtf8(std::filesystem::path("abc")), "abc"); + EXPECT_EQ(PathToUtf8(std::filesystem::path(u"\x2603")), "\xe2\x98\x83"); +} + } // namespace testing } // namespace fml diff --git a/engine/src/flutter/impeller/toolkit/interop/README.md b/engine/src/flutter/impeller/toolkit/interop/README.md index 6e75a53a11775..279379217e143 100644 --- a/engine/src/flutter/impeller/toolkit/interop/README.md +++ b/engine/src/flutter/impeller/toolkit/interop/README.md @@ -27,7 +27,7 @@ A single-header C API for 2D graphics and text rendering. [Impeller](../../READM Users may plug in a custom toolchain into the Flutter Engine build system to build the `libimpeller.so` dynamic library. However, for the common platforms, the CI bots upload a tarball containing the library and headers. This URL for the SDK tarball for a particular platform can be constructed as follows: ```sh -https://storage.googleapis.com/flutter_infra_release/flutter/$FLUTTER_SHA/$PLATFORM_ARCH/impeller_sdk.zip +https://download.shorebird.dev/flutter_infra_release/flutter/$FLUTTER_SHA/$PLATFORM_ARCH/impeller_sdk.zip ``` The `$FLUTTER_SHA` is the Git hash in the [Flutter repository](https://github.com/flutter/flutter). The `$PLATFORM_ARCH` can be determined from the table below. diff --git a/engine/src/flutter/lib/io/dart_io.cc b/engine/src/flutter/lib/io/dart_io.cc index 75bb37e898135..9c8b90dcf4a44 100644 --- a/engine/src/flutter/lib/io/dart_io.cc +++ b/engine/src/flutter/lib/io/dart_io.cc @@ -17,10 +17,13 @@ namespace flutter { void DartIO::InitForIsolate(bool may_insecurely_connect_to_all_domains, const std::string& domain_network_policy) { + // TODO(https://dartbug.com/61694): move this code into dart_io_api.h Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io")); Dart_Handle result = Dart_SetNativeResolver(io_lib, dart::bin::LookupIONative, dart::bin::LookupIONativeSymbol); FML_CHECK(!CheckAndHandleError(result)); + result = Dart_SetFfiNativeResolver(io_lib, dart::bin::LookupIOFfiNative); + FML_CHECK(!CheckAndHandleError(result)); Dart_Handle ui_lib = Dart_LookupLibrary(ToDart("dart:ui")); Dart_Handle dart_validate_args[1]; diff --git a/engine/src/flutter/lib/snapshot/BUILD.gn b/engine/src/flutter/lib/snapshot/BUILD.gn index e4b52cac21985..e495383162a89 100644 --- a/engine/src/flutter/lib/snapshot/BUILD.gn +++ b/engine/src/flutter/lib/snapshot/BUILD.gn @@ -35,7 +35,10 @@ group("generate_snapshot_bins") { if (host_os == "mac" && (target_os == "mac" || target_os == "ios" || target_os == "android")) { # For macOS target builds: needed for both target CPUs (arm64, x64). - public_deps += [ ":create_macos_gen_snapshots" ] + public_deps += [ + ":create_macos_analyze_snapshots", + ":create_macos_gen_snapshots", + ] } else if (host_os == "mac" && (target_cpu == "arm" || target_cpu == "arm64")) { # For iOS, Android target builds: all AOT target CPUs are arm/arm64. @@ -46,9 +49,11 @@ group("generate_snapshot_bins") { public_deps = [ "$dart_src/runtime/bin:gen_snapshot($host_toolchain)" ] } - # Build analyze_snapshot for 64-bit target CPUs. - if (host_os == "linux" && (target_cpu == "x64" || target_cpu == "arm64" || - target_cpu == "riscv64")) { + # Build analyze_snapshot for 64-bit target CPUs on linux. + # Or always targeting arm64 for Shorebird builds. + if ((host_os == "linux" && + (target_cpu == "x64" || target_cpu == "riscv64")) || + target_cpu == "arm64") { public_deps += [ "$dart_src/runtime/bin:analyze_snapshot($host_toolchain)" ] } } @@ -257,6 +262,69 @@ if (host_os == "mac" && ":create_macos_gen_snapshot_x64${gen_snapshot_suffix}", ] } + + # Added by shorebird. + # analyze_snapshot targets below were copied from the gen_snapshot targets + # above to allow us to include analyze_snapshot in the artifacts generated + # for create_ios_framework.py. + template("build_mac_analyze_snapshot") { + assert(defined(invoker.host_arch)) + host_cpu = invoker.host_arch + + build_toolchain = "//build/toolchain/mac:clang_$host_cpu" + analyze_snapshot_target_name = "analyze_snapshot" + + # At this point, the gen_snapshot equivalent changes + # gen_ snapshot_target_name to "gen_snapshot_host_targeting_host". There is + # no equivalent for analyze_snapshot, so we don't do that here. + # + # It's unclear whether we need to do so now, but we didn't previously, so + # we're not doing it now until we have a reason to. + + analyze_snapshot_target = + "$dart_src/runtime/bin:$analyze_snapshot_target_name($build_toolchain)" + + copy(target_name) { + # The toolchain-specific output directory. For cross-compiles, this is a + # clang-x64 or clang-arm64 subdirectory of the top-level build directory. + output_dir = get_label_info(analyze_snapshot_target, "root_out_dir") + + sources = [ "${output_dir}/${analyze_snapshot_target_name}" ] + outputs = [ + "${root_out_dir}/artifacts_$host_cpu/analyze_snapshot_${target_cpu}", + ] + deps = [ analyze_snapshot_target ] + } + } + + build_mac_analyze_snapshot( + "create_macos_analyze_snapshot_arm64_${target_cpu}") { + host_arch = "arm64" + } + + build_mac_analyze_snapshot( + "create_macos_analyze_snapshot_x64_${target_cpu}") { + host_arch = "x64" + } + + action("create_macos_analyze_snapshots") { + script = "//flutter/sky/tools/create_macos_binary.py" + outputs = [ "${root_out_dir}/analyze_snapshot_${target_cpu}" ] + args = [ + "--in-arm64", + rebase_path( + "${root_out_dir}/artifacts_arm64/analyze_snapshot_${target_cpu}"), + "--in-x64", + rebase_path( + "${root_out_dir}/artifacts_x64/analyze_snapshot_${target_cpu}"), + "--out", + rebase_path("${root_out_dir}/analyze_snapshot_${target_cpu}"), + ] + deps = [ + ":create_macos_analyze_snapshot_arm64_${target_cpu}", + ":create_macos_analyze_snapshot_x64_${target_cpu}", + ] + } } source_set("snapshot") { diff --git a/engine/src/flutter/lib/web_ui/dev/generate_builder_json.dart b/engine/src/flutter/lib/web_ui/dev/generate_builder_json.dart index d97bdc9f9663c..4809fa9e6d3b6 100644 --- a/engine/src/flutter/lib/web_ui/dev/generate_builder_json.dart +++ b/engine/src/flutter/lib/web_ui/dev/generate_builder_json.dart @@ -100,7 +100,7 @@ class GenerateBuilderJsonCommand extends Command { packageLock, 'Mac', BrowserName.safari, - specificOS: 'Mac-14|Mac-15', + specificOS: 'Mac-15.5|Mac-15.7', cpu: 'arm64', ), ]; diff --git a/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart b/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart index d0629b34a67a2..ad41bb65df7b8 100644 --- a/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart +++ b/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart @@ -56,7 +56,7 @@ class CopyArtifactsStep implements PipelineStep { ), }; final Uri url = Uri.https( - 'storage.googleapis.com', + 'download.shorebird.dev', '${realmComponent}flutter_infra_release/flutter/${realm == LuciRealm.Try ? gitRevision : contentHash}/flutter-web-sdk.zip', ); final http.Response response = await http.Client().get(url); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart index 5e2bf758bef0b..ad4d9b0f87386 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart @@ -69,7 +69,7 @@ class EngineFlutterView implements ui.FlutterView { // hot restart. embeddingStrategy.attachViewRoot(dom.rootElement); pointerBinding = PointerBinding(this); - _resizeSubscription = onResize.listen(_didResize); + _resizeSubscription = onResize.listen(_handleBrowserResize); _globalHtmlAttributes.applyAttributes( viewId: viewId, rendererTag: renderer.rendererTag, @@ -120,7 +120,7 @@ class EngineFlutterView implements ui.FlutterView { void render(ui.Scene scene, {ui.Size? size}) { assert(!isDisposed, 'Trying to render a disposed EngineFlutterView.'); if (size != null) { - resize(size); + handleFrameworkResize(size); } platformDispatcher.render(scene, this); } @@ -198,15 +198,27 @@ class EngineFlutterView implements ui.FlutterView { /// hiding `overflow`). Flutter does not attempt to interpret the styles of /// `hostElement` to compute its `physicalConstraints`, only its current size. @visibleForTesting - void resize(ui.Size newPhysicalSize) { + void handleFrameworkResize(ui.Size newPhysicalSize) { + // TODO(mdebbar): This resizing is only needed for the multiview mode. Should we make it a no-op + // in the full page mode to avoid doing unnecessary work? + // The browser uses CSS, and CSS operates in logical sizes. final ui.Size logicalSize = newPhysicalSize / devicePixelRatio; dom.rootElement.style ..width = '${logicalSize.width}px' ..height = '${logicalSize.height}px'; - // Force an update of the physicalSize so it's ready for the renderer. - _physicalSize = _computePhysicalSize(); + // When the keyboard is active on mobile, we explicitly do not update + // `_physicalSize`. This is because `_handleBrowserResize` (the method + // that handles browser-initiated resizes) has special logic to + // keep `_physicalSize` stale (large) and instead rely on `viewInsets` + // to shrink the visible area. If `_handleFrameworkResize` were to update `_physicalSize` + // to the smaller visible size, it would break the `viewInsets` logic + // on subsequent calculations. + if (!_shouldPreservePhysicalSizeOnResize) { + // Force an update of the physicalSize so it's ready for the renderer. + _physicalSize = _computePhysicalSize(); + } } /// Lazily populated and cleared at the end of the frame. @@ -264,7 +276,14 @@ class EngineFlutterView implements ui.FlutterView { Stream get onResize => dimensionsProvider.onResize; - /// Called immediately after the view has been resized. + /// Whether to preserve the physical size of the view when the browser window + /// resizes. + /// + /// This is used to prevent the view from resizing when the on-screen keyboard + /// appears on mobile devices. + bool get _shouldPreservePhysicalSizeOnResize => isMobile && textEditing.isEditing; + + /// Called immediately after the view has been resized by the browser. /// /// When there is a text editing going on in mobile devices, do not change /// the physicalSize, change the [window.viewInsets]. See: @@ -273,12 +292,17 @@ class EngineFlutterView implements ui.FlutterView { /// /// Note: always check for rotations for a mobile device. Update the physical /// size if the change is caused by a rotation. - void _didResize(ui.Size? newSize) { + /// + /// When `_shouldPreservePhysicalSizeOnResize` is true (i.e., keyboard is active + /// on mobile), `_physicalSize` is deliberately kept stale (representing the + /// full screen size) while `viewInsets` are updated to reflect the keyboard's + /// presence. This allows the framework to correctly shrink its content using + /// `resizeToAvoidBottomInset`. When the keyboard is dismissed, `_physicalSize` + /// is updated to the actual new physical size of the window. + void _handleBrowserResize(ui.Size? _) { StyleManager.scaleSemanticsHost(dom.semanticsHost, devicePixelRatio); final ui.Size newPhysicalSize = _computePhysicalSize(); - final bool isEditingOnMobile = - isMobile && !_isRotation(newPhysicalSize) && textEditing.isEditing; - if (isEditingOnMobile) { + if (_shouldPreservePhysicalSizeOnResize && !_isRotation(newPhysicalSize)) { _computeOnScreenKeyboardInsets(true); } else { _physicalSize = newPhysicalSize; @@ -328,6 +352,13 @@ class EngineFlutterView implements ui.FlutterView { _physicalSize!.height, isEditingOnMobile, ); + + // Ensure that viewInsets are never negative. If it's not caught here, it will be caught later + // in the framework, and will be hard to debug since the root cause is here. + assert( + _viewInsets.isNonNegative, + 'ViewInsets cannot be negative. This is usually caused by an incorrect physicalSize calculation when the keyboard is being dismissed.', + ); } } @@ -697,6 +728,9 @@ class ViewPadding implements ui.ViewPadding { final double right; @override final double bottom; + + /// Returns true if all padding values are non-negative. + bool get isNonNegative => left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0; } class ViewConstraints implements ui.ViewConstraints { diff --git a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart index 60e1a1b5b5984..f6a5a24985008 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart @@ -11,6 +11,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../common/matchers.dart'; import '../common/test_initialization.dart'; @@ -25,7 +26,7 @@ void main() { internalBootstrapBrowserTest(() => testMain); } -Future testMain() async { +void testMain() { setUpImplicitView(); test('onTextScaleFactorChanged preserves the zone', () { @@ -520,33 +521,30 @@ Future testMain() async { domWindow['screen'] = original; }); - test( - 'SingletonFlutterWindow implements locale, locales, and locale change notifications', - () async { - // This will count how many times we notified about locale changes. - int localeChangedCount = 0; - myWindow.onLocaleChanged = () { - localeChangedCount += 1; - }; + test('SingletonFlutterWindow implements locale, locales, and locale change notifications', () { + // This will count how many times we notified about locale changes. + int localeChangedCount = 0; + myWindow.onLocaleChanged = () { + localeChangedCount += 1; + }; - // We populate the initial list of locales automatically (only test that we - // got some locales; some contributors may be in different locales, so we - // can't test the exact contents). - expect(myWindow.locale, isA()); - expect(myWindow.locales, isNotEmpty); - - // Trigger a change notification (reset locales because the notification - // doesn't actually change the list of languages; the test only observes - // that the list is populated again). - EnginePlatformDispatcher.instance.debugResetLocales(); - expect(myWindow.locales, isEmpty); - expect(myWindow.locale, equals(const ui.Locale.fromSubtags())); - expect(localeChangedCount, 0); - domWindow.dispatchEvent(createDomEvent('Event', 'languagechange')); - expect(myWindow.locales, isNotEmpty); - expect(localeChangedCount, 1); - }, - ); + // We populate the initial list of locales automatically (only test that we + // got some locales; some contributors may be in different locales, so we + // can't test the exact contents). + expect(myWindow.locale, isA()); + expect(myWindow.locales, isNotEmpty); + + // Trigger a change notification (reset locales because the notification + // doesn't actually change the list of languages; the test only observes + // that the list is populated again). + EnginePlatformDispatcher.instance.debugResetLocales(); + expect(myWindow.locales, isEmpty); + expect(myWindow.locale, equals(const ui.Locale.fromSubtags())); + expect(localeChangedCount, 0); + domWindow.dispatchEvent(createDomEvent('Event', 'languagechange')); + expect(myWindow.locales, isNotEmpty); + expect(localeChangedCount, 1); + }); test('dispatches browser event on flutter/service_worker channel', () async { final Completer completer = Completer(); @@ -742,7 +740,7 @@ Future testMain() async { ..height = 'auto'; // Resize the host to 20x20 (physical pixels). - view.resize(const ui.Size.square(50)); + view.handleFrameworkResize(const ui.Size.square(50)); // The view's physicalSize should be updated too. expect(view.physicalSize, const ui.Size(50.0, 50.0)); @@ -776,7 +774,7 @@ Future testMain() async { EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(null); }); - test('JsViewConstraints are passed and used to compute physicalConstraints', () async { + test('JsViewConstraints are passed and used to compute physicalConstraints', () { view = EngineFlutterView( EnginePlatformDispatcher.instance, host, @@ -800,4 +798,28 @@ Future testMain() async { ); }); }); + + group('keyboard resize behavior', () { + setUp(() { + // Simulate keyboard being up. + textEditing.isEditing = true; + ui_web.browser.debugOperatingSystemOverride = ui_web.OperatingSystem.android; + }); + + tearDown(() { + textEditing.isEditing = false; + ui_web.browser.debugOperatingSystemOverride = null; + }); + + test('physicalSize remains unchanged when keyboard is up', () { + final ui.Size initialPhysicalSize = myWindow.physicalSize; + + // Pick a smaller size. + final ui.Size newSize = initialPhysicalSize ~/ 2; + myWindow.handleFrameworkResize(newSize); + + // View's `physicalSize` should remain unchanged. + expect(myWindow.physicalSize, initialPhysicalSize); + }); + }); } diff --git a/engine/src/flutter/lib/web_ui/test/ui/web_paragraph/font_collection_test.dart b/engine/src/flutter/lib/web_ui/test/webparagraph/font_collection_test.dart similarity index 98% rename from engine/src/flutter/lib/web_ui/test/ui/web_paragraph/font_collection_test.dart rename to engine/src/flutter/lib/web_ui/test/webparagraph/font_collection_test.dart index 4e00dc720a27c..af0ecf6bd72ba 100644 --- a/engine/src/flutter/lib/web_ui/test/ui/web_paragraph/font_collection_test.dart +++ b/engine/src/flutter/lib/web_ui/test/webparagraph/font_collection_test.dart @@ -8,8 +8,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import '../../common/fake_asset_manager.dart'; -import '../../common/test_initialization.dart'; +import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); diff --git a/engine/src/flutter/runtime/BUILD.gn b/engine/src/flutter/runtime/BUILD.gn index 760cb5c318b98..9f9444b607aa6 100644 --- a/engine/src/flutter/runtime/BUILD.gn +++ b/engine/src/flutter/runtime/BUILD.gn @@ -118,6 +118,10 @@ source_set("runtime") { "//flutter/third_party/tonic", "//flutter/txt", ] + + if (is_ios) { + deps += [ "//flutter/runtime/shorebird:patch_cache" ] + } } if (enable_unittests) { diff --git a/engine/src/flutter/runtime/dart_isolate.cc b/engine/src/flutter/runtime/dart_isolate.cc index 521c284f1c905..c81ab7c7bd44d 100644 --- a/engine/src/flutter/runtime/dart_isolate.cc +++ b/engine/src/flutter/runtime/dart_isolate.cc @@ -1108,7 +1108,9 @@ Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback( advisory_script_entrypoint, parent_group_data.GetChildIsolatePreparer(), parent_group_data.GetIsolateCreateCallback(), - parent_group_data.GetIsolateShutdownCallback()))); + parent_group_data.GetIsolateShutdownCallback(), + nullptr // native_assets_manager + ))); TaskRunners null_task_runners(advisory_script_uri, /* platform= */ nullptr, diff --git a/engine/src/flutter/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index 198a2e75a7edc..fc70f63a346f2 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -6,6 +6,7 @@ #include +#include #include "flutter/fml/native_library.h" #include "flutter/fml/paths.h" #include "flutter/fml/trace_event.h" @@ -13,6 +14,11 @@ #include "flutter/runtime/dart_vm.h" #include "third_party/dart/runtime/include/dart_api.h" +#if SHOREBIRD_USE_INTERPRETER +#include "flutter/runtime/shorebird/patch_cache.h" // nogncheck +#endif +#include "flutter/shell/common/shorebird/updater.h" // nogncheck + namespace flutter { const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData"; @@ -145,7 +151,20 @@ static std::shared_ptr ResolveIsolateData( nullptr, // release_func true // dontneed_safe ); -#else // DART_SNAPSHOT_STATIC_LINK +#else // DART_SNAPSHOT_STATIC_LINK + // Tell the Rust updater we're booting from whatever patch it selected. + // This copies next_boot โ†’ current_boot in the Rust state. The call is + // guarded inside Updater to execute at most once per process โ€” see the + // Updater class comment for why this matters in add-to-app and + // FlutterEngineGroup scenarios. + shorebird::Updater::Instance().ReportLaunchStart(); +#if SHOREBIRD_USE_INTERPRETER + // Try loading from a Shorebird patch first. + if (auto mapping = TryLoadFromPatch(settings.application_library_paths, + DartSnapshot::kIsolateDataSymbol)) { + return mapping; + } +#endif // SHOREBIRD_USE_INTERPRETER return SearchMapping( settings.isolate_snapshot_data, // embedder_mapping_callback settings.isolate_snapshot_data_path, // file_path @@ -165,7 +184,15 @@ static std::shared_ptr ResolveIsolateInstructions( nullptr, // release_func true // dontneed_safe ); -#else // DART_SNAPSHOT_STATIC_LINK +#else // DART_SNAPSHOT_STATIC_LINK +#if SHOREBIRD_USE_INTERPRETER + // Try loading from a Shorebird patch first. + if (auto mapping = + TryLoadFromPatch(settings.application_library_paths, + DartSnapshot::kIsolateInstructionsSymbol)) { + return mapping; + } +#endif // SHOREBIRD_USE_INTERPRETER return SearchMapping( settings.isolate_snapshot_instr, // embedder_mapping_callback settings.isolate_snapshot_instr_path, // file_path diff --git a/engine/src/flutter/runtime/shorebird/BUILD.gn b/engine/src/flutter/runtime/shorebird/BUILD.gn new file mode 100644 index 0000000000000..1f856e36d3f48 --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/BUILD.gn @@ -0,0 +1,16 @@ +import("//flutter/common/config.gni") + +source_set("patch_cache") { + sources = [ + "patch_cache.cc", + "patch_cache.h", + "patch_mapping.cc", + "patch_mapping.h", + ] + + deps = [ + "//flutter/fml", + "//flutter/runtime:libdart", + "//flutter/shell/common/shorebird:updater", + ] +} diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.cc b/engine/src/flutter/runtime/shorebird/patch_cache.cc new file mode 100644 index 0000000000000..8c5cc3a83f182 --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -0,0 +1,165 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/shorebird/patch_cache.h" + +#include + +#include "flutter/fml/logging.h" +#include "flutter/fml/mapping.h" +#include "flutter/runtime/shorebird/patch_mapping.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace flutter { + +namespace { + +// These symbol names match the constants in dart_snapshot.cc. +// We duplicate them here rather than extracting them into a header. +// They are actually defined down in Dart and will never change. +constexpr const char* kIsolateDataSymbol = "kDartIsolateSnapshotData"; +constexpr const char* kIsolateInstructionsSymbol = + "kDartIsolateSnapshotInstructions"; + +} // namespace + +// PatchCacheEntry implementation + +std::shared_ptr PatchCacheEntry::Create( + const std::string& path) { + // vmcode files currently use ELF internally after a prefix of a Shorebird + // linker header. + auto elf_mapping = fml::FileMapping::CreateReadOnly(path); + if (!elf_mapping) { + FML_LOG(ERROR) << "Failed to map file: " << path; + return nullptr; + } + + int elf_file_offset = Shorebird_ReadLinkHeader(elf_mapping->GetMapping(), + elf_mapping->GetSize()); + + const char* error = nullptr; + // The VM Snapshot is identical for all binaries produced by a given version + // of Dart. Our linker checks this and will fail to link if ever the VM + // snapshot changes. We ignore the VM data/instrs here. + const uint8_t* ignored_vm_data = nullptr; + const uint8_t* ignored_vm_instrs = nullptr; + const uint8_t* isolate_data = nullptr; + const uint8_t* isolate_instrs = nullptr; + + Dart_LoadedElf* elf = Dart_LoadELF( + path.c_str(), elf_file_offset, &error, &ignored_vm_data, + &ignored_vm_instrs, &isolate_data, &isolate_instrs, dart::bin::kReadOnly); + + if (elf == nullptr) { + FML_LOG(ERROR) << "Failed to load patch at " << path << " error: " << error; + return nullptr; + } + + FML_LOG(INFO) << "Loaded patch from " << path; + + return std::shared_ptr( + new PatchCacheEntry(path, elf, isolate_data, isolate_instrs)); +} + +PatchCacheEntry::PatchCacheEntry(const std::string& path, + Dart_LoadedElf* elf, + const uint8_t* isolate_data, + const uint8_t* isolate_instrs) + : path_(path), + elf_(elf), + isolate_data_(isolate_data), + isolate_instrs_(isolate_instrs) {} + +PatchCacheEntry::~PatchCacheEntry() { + if (elf_ != nullptr) { + FML_LOG(INFO) << "Unloading patch from " << path_; + Dart_UnloadELF(elf_); + elf_ = nullptr; + } +} + +PatchCache& PatchCache::Instance() { + static PatchCache instance; + return instance; +} + +std::shared_ptr PatchCache::GetOrLoad( + const std::string& path) { + std::lock_guard lock(mutex_); + + // Check if we have a cached entry that's still alive + auto it = cache_.find(path); + if (it != cache_.end()) { + if (auto entry = it->second.lock()) { + FML_LOG(INFO) << "PatchCache hit for " << path; + return entry; + } + // Entry expired, remove it + cache_.erase(it); + } + + // Load a new entry + auto entry = PatchCacheEntry::Create(path); + if (entry) { + cache_[path] = entry; // Store weak_ptr + } + + return entry; +} + +void PatchCache::PruneExpired() { + std::lock_guard lock(mutex_); + + for (auto it = cache_.begin(); it != cache_.end();) { + if (it->second.expired()) { + it = cache_.erase(it); + } else { + ++it; + } + } +} + +std::shared_ptr TryLoadFromPatch( + const std::vector& native_library_paths, + const char* symbol_name) { + if (native_library_paths.empty()) { + return nullptr; + } + + // Check if the first path is a Shorebird patch (.vmcode file) + const auto& patch_path = native_library_paths.front(); + bool is_patch = patch_path.find(".vmcode") != std::string::npos; + if (!is_patch) { + return nullptr; + } + + // Patches only contain isolate data/instructions, not VM data/instructions. + // Return nullptr for VM symbols to allow fallback to the base app. + std::string symbol(symbol_name); + if (symbol != kIsolateDataSymbol && symbol != kIsolateInstructionsSymbol) { + return nullptr; + } + + // Load the patch using the cache. + auto cache_entry = PatchCache::Instance().GetOrLoad(patch_path); + if (!cache_entry) { + FML_LOG(FATAL) << "Failed to load symbol from patch at " << patch_path; + return nullptr; + } + + FML_LOG(INFO) << "Loading symbol from patch: " << symbol_name; + + // ReportLaunchStart is now called from ResolveIsolateData in + // dart_snapshot.cc, which runs before TryLoadFromPatch on all platforms. + + if (symbol == kIsolateDataSymbol) { + return PatchMapping::CreateIsolateData(cache_entry); + } else { + FML_CHECK(symbol == kIsolateInstructionsSymbol); + return PatchMapping::CreateIsolateInstructions(cache_entry); + } +} + +} // namespace flutter diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.h b/engine/src/flutter/runtime/shorebird/patch_cache.h new file mode 100644 index 0000000000000..1f2e14fab711d --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/patch_cache.h @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_RUNTIME_SHOREBIRD_PATCH_CACHE_H_ +#define FLUTTER_RUNTIME_SHOREBIRD_PATCH_CACHE_H_ + +#include +#include +#include +#include +#include + +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" + +namespace flutter { + +/// A cache entry that holds a loaded patch file and its extracted snapshot +/// pointers. The patch is automatically unloaded when the last reference to +/// this entry is released. +class PatchCacheEntry { + public: + /// Creates a new cache entry by loading the patch file at the given path. + /// Returns nullptr if loading fails. + static std::shared_ptr Create(const std::string& path); + + ~PatchCacheEntry(); + + /// Returns the isolate snapshot data pointer. + const uint8_t* isolate_data() const { return isolate_data_; } + + /// Returns the isolate snapshot instructions pointer. + const uint8_t* isolate_instructions() const { return isolate_instrs_; } + + /// Returns the path this entry was loaded from. + const std::string& path() const { return path_; } + + private: + PatchCacheEntry(const std::string& path, + Dart_LoadedElf* elf, + const uint8_t* isolate_data, + const uint8_t* isolate_instrs); + + std::string path_; + Dart_LoadedElf* elf_; + const uint8_t* isolate_data_; + const uint8_t* isolate_instrs_; + + FML_DISALLOW_COPY_AND_ASSIGN(PatchCacheEntry); +}; + +/// A thread-safe cache for loaded patch files. Cache entries are automatically +/// removed when all references to them are released. +class PatchCache { + public: + /// Returns the singleton instance of the cache. + static PatchCache& Instance(); + + /// Gets or loads a patch file at the given path. If the file is already + /// cached and the entry is still alive, returns the existing entry. + /// Otherwise, loads the file and creates a new cache entry. + /// Returns nullptr if loading fails. + std::shared_ptr GetOrLoad(const std::string& path); + + /// Removes expired entries from the cache. This is called automatically + /// by GetOrLoad, but can also be called explicitly. + void PruneExpired(); + + private: + PatchCache() = default; + ~PatchCache() = default; + + std::mutex mutex_; + // We store weak references so entries are automatically cleaned up when + // all ElfMapping instances release their references. + std::map> cache_; + + FML_DISALLOW_COPY_AND_ASSIGN(PatchCache); +}; + +/// Checks if the first path in native_library_paths is a Shorebird patch +/// (.vmcode file) and if so, attempts to load the requested symbol from +/// the patch. +/// +/// @param native_library_paths The list of library paths to check. The first +/// path is checked for the .vmcode extension. +/// @param symbol_name The symbol to load (kIsolateDataSymbol or +/// kIsolateInstructionsSymbol). +/// @return A mapping for the requested symbol if this is a patch and the +/// symbol is available in the patch, nullptr otherwise. +/// +/// Note: Patches only contain isolate data/instructions, not VM +/// data/instructions. For VM symbols, this will always return nullptr, +/// allowing the caller to fall back to loading from the base app. +std::shared_ptr TryLoadFromPatch( + const std::vector& native_library_paths, + const char* symbol_name); + +} // namespace flutter + +#endif // FLUTTER_RUNTIME_SHOREBIRD_PATCH_CACHE_H_ diff --git a/engine/src/flutter/runtime/shorebird/patch_mapping.cc b/engine/src/flutter/runtime/shorebird/patch_mapping.cc new file mode 100644 index 0000000000000..d444cda817c34 --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/patch_mapping.cc @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/shorebird/patch_mapping.h" + +#include "third_party/dart/runtime/include/dart_native_api.h" + +namespace flutter { + +std::shared_ptr PatchMapping::CreateIsolateData( + std::shared_ptr entry) { + if (!entry) { + return nullptr; + } + const uint8_t* data = entry->isolate_data(); + size_t size = Dart_SnapshotDataSize(data); + return std::shared_ptr(new PatchMapping(entry, data, size)); +} + +std::shared_ptr PatchMapping::CreateIsolateInstructions( + std::shared_ptr entry) { + if (!entry) { + return nullptr; + } + const uint8_t* data = entry->isolate_instructions(); + size_t size = Dart_SnapshotInstrSize(data); + return std::shared_ptr(new PatchMapping(entry, data, size)); +} + +PatchMapping::PatchMapping(std::shared_ptr entry, + const uint8_t* data, + size_t size) + : cache_entry_(std::move(entry)), data_(data), size_(size) {} + +PatchMapping::~PatchMapping() = default; + +size_t PatchMapping::GetSize() const { + return size_; +} + +const uint8_t* PatchMapping::GetMapping() const { + return data_; +} + +bool PatchMapping::IsDontNeedSafe() const { + // Patch mappings are file-backed and safe for madvise(DONTNEED). + return true; +} + +} // namespace flutter diff --git a/engine/src/flutter/runtime/shorebird/patch_mapping.h b/engine/src/flutter/runtime/shorebird/patch_mapping.h new file mode 100644 index 0000000000000..8c2e494a9004c --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/patch_mapping.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_RUNTIME_SHOREBIRD_PATCH_MAPPING_H_ +#define FLUTTER_RUNTIME_SHOREBIRD_PATCH_MAPPING_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" +#include "flutter/runtime/shorebird/patch_cache.h" + +namespace flutter { + +/// A Mapping implementation that references data from a cached patch file. +/// Holding a reference to this mapping keeps the underlying patch loaded. +class PatchMapping final : public fml::Mapping { + public: + /// Creates a mapping for the isolate snapshot data from the given cache + /// entry. + static std::shared_ptr CreateIsolateData( + std::shared_ptr entry); + + /// Creates a mapping for the isolate snapshot instructions from the given + /// cache entry. + static std::shared_ptr CreateIsolateInstructions( + std::shared_ptr entry); + + ~PatchMapping() override; + + // |fml::Mapping| + size_t GetSize() const override; + + // |fml::Mapping| + const uint8_t* GetMapping() const override; + + // |fml::Mapping| + bool IsDontNeedSafe() const override; + + private: + PatchMapping(std::shared_ptr entry, + const uint8_t* data, + size_t size); + + std::shared_ptr cache_entry_; + const uint8_t* data_; + size_t size_; + + FML_DISALLOW_COPY_AND_ASSIGN(PatchMapping); +}; + +} // namespace flutter + +#endif // FLUTTER_RUNTIME_SHOREBIRD_PATCH_MAPPING_H_ diff --git a/engine/src/flutter/shell/common/BUILD.gn b/engine/src/flutter/shell/common/BUILD.gn index 78f52396582f6..11af400ec6290 100644 --- a/engine/src/flutter/shell/common/BUILD.gn +++ b/engine/src/flutter/shell/common/BUILD.gn @@ -148,6 +148,7 @@ source_set("common") { "//flutter/lib/ui", "//flutter/runtime", "//flutter/shell/common:base64", + "//flutter/shell/common/shorebird:updater", "//flutter/shell/geometry", "//flutter/shell/profiling", "//flutter/skia", @@ -337,6 +338,7 @@ if (enable_unittests) { "//flutter/common/graphics", "//flutter/display_list/testing:display_list_testing", "//flutter/shell/common:base64", + "//flutter/shell/common/shorebird:updater", "//flutter/shell/profiling:profiling_unittests", "//flutter/shell/version", "//flutter/testing:fixture_test", diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 73d05330599da..57d751b19f578 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -46,6 +46,8 @@ #include "third_party/skia/include/core/SkGraphics.h" #include "third_party/tonic/common/log.h" +#include "flutter/shell/common/shorebird/updater.h" + namespace flutter { constexpr char kSkiaChannel[] = "flutter/skia"; @@ -521,6 +523,18 @@ Shell::Shell(DartVMRef vm, is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)), weak_factory_gpu_(nullptr), weak_factory_(this) { + // Report launch outcome to the Shorebird updater for crash recovery. + // If the VM failed to start, we report failure so the updater can roll + // back the patch. These calls are guarded inside Updater to execute at + // most once per process โ€” only the first Shell's outcome is reported. + // In add-to-app, subsequent engines are silently ignored since they + // boot from the same snapshot that was already reported on. + // On unsupported platforms, NoOpUpdater handles these calls gracefully. + if (!vm_) { + shorebird::Updater::Instance().ReportLaunchFailure(); + } else { + shorebird::Updater::Instance().ReportLaunchSuccess(); + } FML_CHECK(!settings.enable_software_rendering || !settings.enable_impeller) << "Software rendering is incompatible with Impeller."; if (!settings.enable_impeller && settings.warn_on_impeller_opt_out) { diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index bb57adc49e470..07b9310166b5d 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -52,6 +52,8 @@ #include "third_party/skia/include/codec/SkCodecAnimation.h" #include "third_party/tonic/converter/dart_converter.h" +#include "flutter/shell/common/shorebird/updater.h" + #ifdef SHELL_ENABLE_VULKAN #include "flutter/vulkan/vulkan_application.h" // nogncheck #endif @@ -5107,6 +5109,70 @@ TEST_F(ShellTest, ShoulDiscardLayerTreeIfFrameIsSizedIncorrectly) { DestroyShell(std::move(shell), task_runners); } +// Test the full boot flow: ReportLaunchStart is called from +// ResolveIsolateData, then ReportLaunchSuccess from the Shell constructor. +// Both are guarded to run at most once per process. +TEST_F(ShellTest, ShorebirdBootFlowCallsLaunchStartThenSuccess) { + auto mock = std::make_unique(); + auto* mock_ptr = mock.get(); + shorebird::Updater::SetInstanceForTesting(std::move(mock)); + shorebird::Updater::ResetLaunchStateForTesting(); + + auto settings = CreateSettingsForFixture(); + auto task_runners = GetTaskRunnersForFixture(); + auto shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + const auto& log = mock_ptr->call_log(); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); + + DestroyShell(std::move(shell), task_runners); + shorebird::Updater::ResetLaunchStateForTesting(); + shorebird::Updater::ResetInstanceForTesting(); +} + +// In add-to-app, multiple engines may be created within a single process. +// Only the first engine should report launch start/success to the Rust +// updater. This prevents the updater from promoting a newly-downloaded patch +// to "current_boot" when subsequent engines are still running the original +// snapshot that was selected at process init time. +TEST_F(ShellTest, ShorebirdUpdaterReportsOnlyOnceForMultipleShells) { + auto mock = std::make_unique(); + auto* mock_ptr = mock.get(); + shorebird::Updater::SetInstanceForTesting(std::move(mock)); + shorebird::Updater::ResetLaunchStateForTesting(); + + auto settings = CreateSettingsForFixture(); + + // Create first shell โ€” gets Start + Success + auto task_runners1 = GetTaskRunnersForFixture(); + auto shell1 = CreateShell(settings, task_runners1); + ASSERT_TRUE(shell1); + EXPECT_EQ(mock_ptr->launch_start_count(), 1); + EXPECT_EQ(mock_ptr->launch_success_count(), 1); + + // Create second shell โ€” guarded, no additional Start or Success calls. + auto task_runners2 = GetTaskRunnersForFixture(); + auto shell2 = CreateShell(settings, task_runners2); + ASSERT_TRUE(shell2); + EXPECT_EQ(mock_ptr->launch_start_count(), 1); + EXPECT_EQ(mock_ptr->launch_success_count(), 1); + + // Only one Start+Success pair in the call log. + const auto& log = mock_ptr->call_log(); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); + + DestroyShell(std::move(shell1), task_runners1); + DestroyShell(std::move(shell2), task_runners2); + + shorebird::Updater::ResetLaunchStateForTesting(); + shorebird::Updater::ResetInstanceForTesting(); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/common/shorebird/BUILD.gn b/engine/src/flutter/shell/common/shorebird/BUILD.gn new file mode 100644 index 0000000000000..2b1e29c03512d --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/BUILD.gn @@ -0,0 +1,111 @@ +import("//flutter/common/config.gni") +import("//flutter/testing/testing.gni") + +source_set("snapshots_data_handle") { + sources = [ + "snapshots_data_handle.cc", + "snapshots_data_handle.h", + ] + + deps = [ + "//flutter/fml", + "//flutter/runtime", + "//flutter/runtime:libdart", + "//flutter/shell/common", + ] +} + +# C++ wrapper around the Rust updater C API. +# This provides a testable abstraction layer that can be mocked for testing. +source_set("updater") { + sources = [ + "updater.cc", + "updater.h", + ] + + deps = [ "//flutter/fml" ] + + # For the Rust updater C API (shorebird_report_launch_start, etc.) + include_dirs = [ "//flutter" ] + + # Link the Rust updater static library based on target platform. + if (is_android) { + if (target_cpu == "arm") { + libs = [ "//flutter/third_party/updater/target/armv7-linux-androideabi/release/libupdater.a" ] + } else if (target_cpu == "arm64") { + libs = [ "//flutter/third_party/updater/target/aarch64-linux-android/release/libupdater.a" ] + } else if (target_cpu == "x64") { + libs = [ "//flutter/third_party/updater/target/x86_64-linux-android/release/libupdater.a" ] + } else if (target_cpu == "x86") { + libs = [ "//flutter/third_party/updater/target/i686-linux-android/release/libupdater.a" ] + } + } else if (is_ios) { + if (target_cpu == "arm64") { + libs = [ "//flutter/third_party/updater/target/aarch64-apple-ios/release/libupdater.a" ] + } else if (target_cpu == "x64") { + libs = [ "//flutter/third_party/updater/target/x86_64-apple-ios/release/libupdater.a" ] + } + } else if (is_mac) { + if (target_cpu == "arm64") { + libs = [ "//flutter/third_party/updater/target/aarch64-apple-darwin/release/libupdater.a" ] + } else if (target_cpu == "x64") { + libs = [ "//flutter/third_party/updater/target/x86_64-apple-darwin/release/libupdater.a" ] + } + } else if (is_win) { + if (target_cpu == "x64") { + libs = [ + "userenv.lib", + "//flutter/third_party/updater/target/x86_64-pc-windows-msvc/release/updater.lib", + ] + } + } else if (is_linux) { + if (target_cpu == "x64") { + libs = [ "//flutter/third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a" ] + } + } +} + +source_set("shorebird") { + sources = [ + "shorebird.cc", + "shorebird.h", + ] + + deps = [ + ":snapshots_data_handle", + ":updater", + "//flutter/fml", + "//flutter/runtime", + "//flutter/runtime:libdart", + "//flutter/shell/common", + "//flutter/shell/platform/embedder:embedder_headers", + ] +} + +if (enable_unittests) { + test_fixtures("shorebird_fixtures") { + fixtures = [] + } + + executable("shorebird_unittests") { + testonly = true + + sources = [ + "patch_cache_unittests.cc", + "shorebird_unittests.cc", + "snapshots_data_handle_unittests.cc", + "updater_unittests.cc", + ] + + deps = [ + ":shorebird", + ":shorebird_fixtures", + ":snapshots_data_handle", + ":updater", + "//flutter/runtime", + "//flutter/runtime/shorebird:patch_cache", + "//flutter/testing", + "//flutter/testing:fixture_test", + ] + } +} diff --git a/engine/src/flutter/shell/common/shorebird/patch_cache_unittests.cc b/engine/src/flutter/shell/common/shorebird/patch_cache_unittests.cc new file mode 100644 index 0000000000000..51fc20f9ca562 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/patch_cache_unittests.cc @@ -0,0 +1,70 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/shorebird/patch_cache.h" + +#include +#include + +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +TEST(PatchCache, InstanceReturnsSameInstance) { + PatchCache& instance1 = PatchCache::Instance(); + PatchCache& instance2 = PatchCache::Instance(); + EXPECT_EQ(&instance1, &instance2); +} + +TEST(TryLoadFromPatch, ReturnsNullptrForEmptyPaths) { + std::vector empty_paths; + auto result = TryLoadFromPatch(empty_paths, "kDartIsolateSnapshotData"); + EXPECT_EQ(result, nullptr); +} + +TEST(TryLoadFromPatch, ReturnsNullptrForNonVmcodePath) { + std::vector paths = {"/path/to/some/file.so"}; + auto result = TryLoadFromPatch(paths, "kDartIsolateSnapshotData"); + EXPECT_EQ(result, nullptr); +} + +TEST(TryLoadFromPatch, ReturnsNullptrForVmSymbol) { + // Even with a .vmcode path, VM symbols should return nullptr + // (we can't actually load the file, but we can verify the symbol check) + std::vector paths = {"/path/to/patch.vmcode"}; + + // VM data symbol should return nullptr (patches don't contain VM snapshots) + auto result_vm_data = TryLoadFromPatch(paths, "kDartVmSnapshotData"); + EXPECT_EQ(result_vm_data, nullptr); + + // VM instructions symbol should return nullptr + auto result_vm_instrs = + TryLoadFromPatch(paths, "kDartVmSnapshotInstructions"); + EXPECT_EQ(result_vm_instrs, nullptr); +} + +TEST(TryLoadFromPatch, ReturnsNullptrForUnknownSymbol) { + std::vector paths = {"/path/to/patch.vmcode"}; + auto result = TryLoadFromPatch(paths, "kSomeUnknownSymbol"); + EXPECT_EQ(result, nullptr); +} + +TEST(TryLoadFromPatch, ChecksOnlyFirstPath) { + // Only the first path should be checked for .vmcode extension + std::vector paths = {"/path/to/regular.so", + "/path/to/patch.vmcode"}; + auto result = TryLoadFromPatch(paths, "kDartIsolateSnapshotData"); + // Should return nullptr because first path is not .vmcode + EXPECT_EQ(result, nullptr); +} + +TEST(PatchCache, GetOrLoadReturnsNullptrForNonexistentFile) { + auto result = + PatchCache::Instance().GetOrLoad("/nonexistent/path/to/file.vmcode"); + EXPECT_EQ(result, nullptr); +} + +} // namespace testing +} // namespace flutter diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc new file mode 100644 index 0000000000000..71d336e90f8b0 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -0,0 +1,304 @@ + +#include "flutter/shell/common/shorebird/shorebird.h" + +#include +#include +#include +#include +#include + +#include "flutter/fml/command_line.h" +#include "flutter/fml/file.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/message_loop.h" +#include "flutter/fml/native_library.h" +#include "flutter/fml/paths.h" +#include "flutter/lib/ui/plugins/callback_cache.h" +#include "flutter/runtime/dart_snapshot.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/shorebird/snapshots_data_handle.h" +#include "flutter/shell/common/shorebird/updater.h" +#include "flutter/shell/common/switches.h" +#include "fml/logging.h" +#include "shell/platform/embedder/embedder.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +// Namespaced to avoid Google style warnings. +namespace flutter { + +// Old Android versions (e.g. the v16 ndk Flutter uses) don't always include a +// getauxval symbol, but the Rust ring crate assumes it exists: +// https://github.com/briansmith/ring/blob/fa25bf3a7403c9fe6458cb87bd8427be41225ca2/src/cpu/arm.rs#L22 +// It uses it to determine if the CPU supports AES instructions. +// Making this a weak symbol allows the linker to use a real version instead +// if it can find one. +// BoringSSL just reads from procfs instead, which is what we would do if +// we needed to implement this ourselves. Implementation looks straightforward: +// https://lwn.net/Articles/519085/ +// https://github.com/google/boringssl/blob/6ab4f0ae7f2db96d240eb61a5a8b4724e5a09b2f/crypto/cpu_arm_linux.c +#if defined(__ANDROID__) && defined(__arm__) +extern "C" __attribute__((weak)) unsigned long getauxval(unsigned long type) { + return 0; +} +#endif + +#if SHOREBIRD_USE_INTERPRETER +// Global references to the base (unpatched) snapshots from the App.framework. +// These are process-global because: +// 1. The Shorebird updater library is a process-global singleton with its own +// internal state. FileCallbacksImpl provides it access to the base snapshot +// data for patch generation/validation. +// 2. The base snapshots are immutable (baked into the IPA) so sharing them +// across isolate groups is safe. +// +// Note: This design doesn't support multiple engines with different base +// snapshots, but I'm not aware of any use cases for that on iOS. +static fml::RefPtr vm_snapshot; +static fml::RefPtr isolate_snapshot; + +void SetBaseSnapshot(Settings& settings) { + // These mappings happen to be to static data in the App.framework, but + // we still need to seem to hold onto the DartSnapshot objects to keep + // the mappings alive. + vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings); + isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings); + Shorebird_SetBaseSnapshots(isolate_snapshot->GetDataMapping(), + isolate_snapshot->GetInstructionsMapping(), + vm_snapshot->GetDataMapping(), + vm_snapshot->GetInstructionsMapping()); +} +#endif // SHOREBIRD_USE_INTERPRETER + +class FileCallbacksImpl { + public: + static void* Open(); + static uintptr_t Read(void* file, uint8_t* buffer, uintptr_t length); + static int64_t Seek(void* file, int64_t offset, int32_t whence); + static void Close(void* file); +}; + +shorebird::FileCallbacks ShorebirdFileCallbacks() { + return { + .open = FileCallbacksImpl::Open, + .read = FileCallbacksImpl::Read, + .seek = FileCallbacksImpl::Seek, + .close = FileCallbacksImpl::Close, + }; +} + +// Given the contents of a yaml file, return the given value if it exists, +// otherwise return an empty string. +// Does not support nested keys. +std::string GetValueFromYaml(const std::string& yaml, const std::string& key) { + std::stringstream ss(yaml); + std::string line; + std::string prefix = key + ":"; + while (std::getline(ss, line, '\n')) { + if (line.find(prefix) != std::string::npos) { + auto ret = line.substr(line.find(prefix) + prefix.size()); + + // Remove leading and trailing spaces + while (!ret.empty() && std::isspace(ret.front())) { + ret.erase(0, 1); + } + while (!ret.empty() && std::isspace(ret.back())) { + ret.pop_back(); + } + return ret; + } + } + return ""; +} + +/// Newer api, used by Desktop implementations. +/// Does not directly manipulate Settings. +// TODO(eseidel): Consolidate this with the other ConfigureShorebird() API. +bool ConfigureShorebird(const ShorebirdConfigArgs& args, + std::string& patch_path) { + patch_path = args.release_app_library_path; + auto shorebird_updater_dir_name = "shorebird_updater"; + + // Parse app id from shorebird.yaml + std::string app_id = GetValueFromYaml(args.shorebird_yaml, "app_id"); + if (app_id.empty()) { + FML_LOG(ERROR) << "Shorebird updater: appid not found in shorebird.yaml"; + return false; + } + + auto code_cache_dir = fml::paths::JoinPaths( + {std::move(args.code_cache_path), shorebird_updater_dir_name, app_id}); + auto app_storage_dir = fml::paths::JoinPaths( + {std::move(args.app_storage_path), shorebird_updater_dir_name, app_id}); + + fml::CreateDirectory(fml::paths::GetCachesDirectory(), + {shorebird_updater_dir_name}, + fml::FilePermission::kReadWrite); + + // Combine version and version_code into a single string. + // We could also pass these separately through to the updater if needed. + auto release_version = args.release_version.version; + if (!args.release_version.build_number.empty()) { + release_version += "+" + args.release_version.build_number; + } + + shorebird::AppConfig config; + config.release_version = release_version; + config.original_libapp_paths = {args.release_app_library_path}; + config.app_storage_dir = app_storage_dir; + config.code_cache_dir = code_cache_dir; + config.file_callbacks = ShorebirdFileCallbacks(); + config.yaml_config = args.shorebird_yaml; + + bool init_result = shorebird::Updater::Instance().Init(config); + + // We do not support synchronous updates on launch, it's a terrible UX. + // Users can implement custom check-for-updates using + // package:shorebird_code_push. + // https://github.com/shorebirdtech/shorebird/issues/950 + + FML_LOG(INFO) << "Checking for active patch"; + shorebird::Updater::Instance().ValidateNextBootPatch(); + std::string active_path = shorebird::Updater::Instance().NextBootPatchPath(); + if (!active_path.empty()) { + patch_path = active_path; + FML_LOG(INFO) << "Shorebird updater: patch path: " << patch_path; + } else { + FML_LOG(INFO) << "Shorebird updater: no active patch."; + } + + // Note: shorebird_report_launch_start() is now called from TryLoadFromPatch() + // in runtime/shorebird/patch_cache.cc, right before the patched snapshot is + // actually loaded. This fixes issues with FlutterEngineGroup and other cases + // where ConfigureShorebird() is called but no Shell is created. + if (!init_result) { + return false; + } + + if (shorebird::Updater::Instance().ShouldAutoUpdate()) { + FML_LOG(INFO) << "Starting Shorebird update"; + shorebird::Updater::Instance().StartUpdateThread(); + } else { + FML_LOG(INFO) + << "Shorebird auto_update disabled, not checking for updates."; + } + + return true; +} + +/// Older api used by iOS and Android, directly manipulates Settings. +// TODO(eseidel): Consolidate this with the other ConfigureShorebird() API. +void ConfigureShorebird(std::string code_cache_path, + std::string app_storage_path, + Settings& settings, + const std::string& shorebird_yaml, + const std::string& version, + const std::string& version_code) { + // If you are crashing here, you probably are running Shorebird in a Debug + // config, where the AOT snapshot won't be linked into the process, and thus + // lookups will fail. Change your Scheme to Release to fix: + // https://github.com/flutter/flutter/wiki/Debugging-the-engine#debugging-ios-builds-with-xcode + FML_CHECK(DartSnapshot::VMSnapshotFromSettings(settings)) + << "XCode Scheme must be set to Release to use Shorebird"; + + auto shorebird_updater_dir_name = "shorebird_updater"; + + auto code_cache_dir = fml::paths::JoinPaths( + {std::move(code_cache_path), shorebird_updater_dir_name}); + auto app_storage_dir = fml::paths::JoinPaths( + {std::move(app_storage_path), shorebird_updater_dir_name}); + + fml::CreateDirectory(fml::paths::GetCachesDirectory(), + {shorebird_updater_dir_name}, + fml::FilePermission::kReadWrite); + + // Combine version and version_code into a single string. + // We could also pass these separately through to the updater if needed. + shorebird::AppConfig config; + config.release_version = version + "+" + version_code; + config.original_libapp_paths = settings.application_library_paths; + config.app_storage_dir = app_storage_dir; + config.code_cache_dir = code_cache_dir; + config.file_callbacks = ShorebirdFileCallbacks(); + config.yaml_config = shorebird_yaml; + + bool init_result = shorebird::Updater::Instance().Init(config); + + // We do not support synchronous updates on launch, it's a terrible UX. + // Users can implement custom check-for-updates using + // package:shorebird_code_push. + // https://github.com/shorebirdtech/shorebird/issues/950 + + // We only set the base snapshot on iOS for now. +#if SHOREBIRD_USE_INTERPRETER + SetBaseSnapshot(settings); +#endif + + shorebird::Updater::Instance().ValidateNextBootPatch(); + std::string active_path = shorebird::Updater::Instance().NextBootPatchPath(); + if (!active_path.empty()) { + FML_LOG(INFO) << "Shorebird updater: active path: " << active_path; + +#if SHOREBIRD_USE_INTERPRETER + // On iOS we add the patch to the front of the list instead of clearing + // the list, to allow dart_snapshot.cc to still find the base snapshot + // for the vm isolate. + settings.application_library_paths.insert( + settings.application_library_paths.begin(), active_path); +#else + settings.application_library_paths.clear(); + settings.application_library_paths.emplace_back(active_path); +#endif + } else { + FML_LOG(INFO) << "Shorebird updater: no active patch."; + } + + // Note: shorebird_report_launch_start() is now called from TryLoadFromPatch() + // in runtime/shorebird/patch_cache.cc, right before the patched snapshot is + // actually loaded. This fixes issues with FlutterEngineGroup and other cases + // where ConfigureShorebird() is called but no Shell is created. + + if (!init_result) { + return; + } + + if (shorebird::Updater::Instance().ShouldAutoUpdate()) { + FML_LOG(INFO) << "Starting Shorebird update"; + shorebird::Updater::Instance().StartUpdateThread(); + } else { + FML_LOG(INFO) + << "Shorebird auto_update disabled, not checking for updates."; + } +} + +void* FileCallbacksImpl::Open() { +#if SHOREBIRD_USE_INTERPRETER + return SnapshotsDataHandle::createForSnapshots(*vm_snapshot, + *isolate_snapshot) + .release(); +#else + // SnapshotsDataHandle exists on all platforms (for testing) but is only used + // on iOS. iOS patches are generated from just the Dart parts of the snapshot, + // excluding the Mach-O specific headers which contain dates and paths that + // make them change on every build. + return nullptr; +#endif // SHOREBIRD_USE_INTERPRETER +} + +uintptr_t FileCallbacksImpl::Read(void* file, + uint8_t* buffer, + uintptr_t length) { + return reinterpret_cast(file)->Read(buffer, length); +} + +int64_t FileCallbacksImpl::Seek(void* file, int64_t offset, int32_t whence) { + // Currently we only support blob handles. + return reinterpret_cast(file)->Seek(offset, whence); +} + +void FileCallbacksImpl::Close(void* file) { + delete reinterpret_cast(file); +} + +} // namespace flutter \ No newline at end of file diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.h b/engine/src/flutter/shell/common/shorebird/shorebird.h new file mode 100644 index 0000000000000..ab5c9162ea0f2 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/shorebird.h @@ -0,0 +1,59 @@ +#ifndef FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ +#define FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ + +#include "flutter/common/settings.h" +#include "flutter/fml/memory/ref_ptr.h" +#include "shell/platform/embedder/embedder.h" + +namespace flutter { + +class DartSnapshot; + +/// Version and build number of the release. +/// Used by ShorebirdConfigArgs. +struct ReleaseVersion { + std::string version; + std::string build_number; +}; + +/// Arguments for ConfigureShorebird. +/// Used by Desktop implementations. +struct ShorebirdConfigArgs { + std::string code_cache_path; + std::string app_storage_path; + std::string release_app_library_path; + std::string shorebird_yaml; + ReleaseVersion release_version; + + ShorebirdConfigArgs(std::string code_cache_path, + std::string app_storage_path, + std::string release_app_library_path, + std::string shorebird_yaml, + ReleaseVersion release_version) + : code_cache_path(code_cache_path), + app_storage_path(app_storage_path), + release_app_library_path(release_app_library_path), + shorebird_yaml(shorebird_yaml), + release_version(release_version) {} +}; + +/// Newer api, used by Desktop implementations. +/// Does not directly manipulate Settings. +bool ConfigureShorebird(const ShorebirdConfigArgs& args, + std::string& patch_path); + +/// Older api used by iOS and Android, directly manipulates Settings. +void ConfigureShorebird(std::string code_cache_path, + std::string app_storage_path, + Settings& settings, + const std::string& shorebird_yaml, + const std::string& version, + const std::string& version_code); + +/// Used for reading app_id from shorebird.yaml. +/// Exposed for testing. +std::string GetValueFromYaml(const std::string& yaml, const std::string& key); + +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ diff --git a/engine/src/flutter/shell/common/shorebird/shorebird_unittests.cc b/engine/src/flutter/shell/common/shorebird/shorebird_unittests.cc new file mode 100644 index 0000000000000..7c108ac1e6231 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/shorebird_unittests.cc @@ -0,0 +1,21 @@ +#include "flutter/shell/common/shorebird/shorebird.h" + +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +TEST(Shorebird, GetValueFromYamlValueExists) { + std::string yaml = "appid: com.example.app\nversion: 1.0.0\n"; + std::string key = "appid"; + std::string value = GetValueFromYaml(yaml, key); + EXPECT_EQ(value, "com.example.app"); +} + +TEST(Shorebird, GetValueFromYamlValueDoesNotExist) { + std::string yaml = "appid: com.example.app\nversion: 1.0.0\n"; + std::string key = "appid2"; + std::string value = GetValueFromYaml(yaml, key); + EXPECT_EQ(value, ""); +} +} // namespace testing +} // namespace flutter \ No newline at end of file diff --git a/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.cc b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.cc new file mode 100644 index 0000000000000..0c6c5a45450a1 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.cc @@ -0,0 +1,144 @@ +#include "flutter/shell/common/shorebird/snapshots_data_handle.h" + +#include "third_party/dart/runtime/include/dart_native_api.h" + +namespace flutter { + +static std::unique_ptr DataMapping(const DartSnapshot& snapshot) { + auto ptr = snapshot.GetDataMapping(); + return std::make_unique(ptr, + Dart_SnapshotDataSize(ptr)); +} + +static std::unique_ptr InstructionsMapping( + const DartSnapshot& snapshot) { + auto ptr = snapshot.GetInstructionsMapping(); + return std::make_unique(ptr, + Dart_SnapshotInstrSize(ptr)); +} + +// The size of the snapshot data is the sum of the sizes of the blobs. +size_t SnapshotsDataHandle::FullSize() const { + size_t size = 0; + for (const auto& blob : blobs_) { + size += blob->GetSize(); + } + return size; +} + +// The offset into the snapshots data blobs as though they were a single +// contiguous buffer. +size_t SnapshotsDataHandle::AbsoluteOffsetForIndex(BlobsIndex index) { + if (index.blob >= blobs_.size()) { + FML_LOG(WARNING) << "Blob index " << index.blob + << " is larger than the number of blobs (" << blobs_.size() + << "). Returning full size (" << FullSize() << ")"; + return FullSize(); + } + if (index.offset > blobs_[index.blob]->GetSize()) { + FML_LOG(WARNING) << "Offset for blob " << index.blob << " (" << index.offset + << ") is larger than the blob size (" + << blobs_[index.blob]->GetSize() + << "). Returning index start of next blob"; + return AbsoluteOffsetForIndex({index.blob + 1, 0}); + } + size_t offset = 0; + for (size_t i = 0; i < index.blob; i++) { + offset += blobs_[i]->GetSize(); + } + offset += index.offset; + return offset; +} + +BlobsIndex SnapshotsDataHandle::IndexForAbsoluteOffset(int64_t offset, + BlobsIndex start_index) { + size_t start_offset = AbsoluteOffsetForIndex(start_index); + if (offset < 0) { + if ((size_t)abs(offset) > start_offset) { + FML_LOG(WARNING) + << "Offset is before the beginning of SnapshotsData. Returning 0, 0"; + return {0, 0}; + } + } else if (offset + start_offset >= FullSize()) { + FML_LOG(WARNING) << "Target offset is past the end of SnapshotsData (" + << offset + start_offset << ", blobs size:" << FullSize() + << "). Returning last blob index and offset"; + return {blobs_.size(), blobs_.back()->GetSize()}; + } + + size_t dest_offset = start_offset + offset; + BlobsIndex index = {0, 0}; + for (const auto& blob : blobs_) { + if (dest_offset < blob->GetSize()) { + // The remaining offset is within this blob. + index.offset = dest_offset; + break; + } + + index.blob++; + dest_offset -= blob->GetSize(); + } + return index; +} + +std::unique_ptr SnapshotsDataHandle::createForSnapshots( + const DartSnapshot& vm_snapshot, + const DartSnapshot& isolate_snapshot) { + // This needs to match the order in which the blobs are written out in + // analyze_snapshot --dump_blobs + std::vector> blobs; + blobs.push_back(DataMapping(vm_snapshot)); + blobs.push_back(DataMapping(isolate_snapshot)); + blobs.push_back(InstructionsMapping(vm_snapshot)); + blobs.push_back(InstructionsMapping(isolate_snapshot)); + return std::make_unique(std::move(blobs)); +} + +uintptr_t SnapshotsDataHandle::Read(uint8_t* buffer, uintptr_t length) { + uintptr_t bytes_read = 0; + // Copy current blob from current offset and possibly into the next blob + // until we have read length bytes. + while (bytes_read < length) { + if (current_index_.blob >= blobs_.size()) { + // We have read all blobs. + break; + } + intptr_t remaining_blob_length = + blobs_[current_index_.blob]->GetSize() - current_index_.offset; + if (remaining_blob_length <= 0) { + // We have read all bytes in this blob. + current_index_.blob++; + current_index_.offset = 0; + continue; + } + intptr_t bytes_to_read = fmin(length - bytes_read, remaining_blob_length); + memcpy(buffer + bytes_read, + blobs_[current_index_.blob]->GetMapping() + current_index_.offset, + bytes_to_read); + bytes_read += bytes_to_read; + current_index_.offset += bytes_to_read; + } + + return bytes_read; +} + +int64_t SnapshotsDataHandle::Seek(int64_t offset, int32_t whence) { + BlobsIndex start_index; + switch (whence) { + case SEEK_CUR: + start_index = current_index_; + break; + case SEEK_SET: + start_index = {0, 0}; + break; + case SEEK_END: + start_index = {blobs_.size(), blobs_.back()->GetSize()}; + break; + default: + FML_CHECK(false) << "Unrecognized whence value in Seek: " << whence; + } + current_index_ = IndexForAbsoluteOffset(offset, start_index); + return current_index_.offset; +} + +} // namespace flutter \ No newline at end of file diff --git a/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.h b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.h new file mode 100644 index 0000000000000..50c4b8179b412 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle.h @@ -0,0 +1,48 @@ +#ifndef FLUTTER_SHELL_COMMON_SHOREBIRD_SNAPSHOTS_DATA_HANDLE_H_ +#define FLUTTER_SHELL_COMMON_SHOREBIRD_SNAPSHOTS_DATA_HANDLE_H_ + +#include +#include "flutter/fml/file.h" +#include "flutter/runtime/dart_snapshot.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace flutter { + +// An offset into an indexed collection of buffers. blob is the index of the +// buffer, and offset is the offset into that buffer. +struct BlobsIndex { + size_t blob; + size_t offset; +}; + +// Implements a POSIX file I/O interface which allows us to provide the four +// data blobs of a Dart snapshot (vm_data, vm_instructions, isolate_data, +// isolate_instructions) to Rust as though it were a single piece of memory. +class SnapshotsDataHandle { + public: + // This would ideally be private, but we need to be able to call it from the + // static createForSnapshots method. + explicit SnapshotsDataHandle(std::vector> blobs) + : blobs_(std::move(blobs)) {} + + static std::unique_ptr createForSnapshots( + const DartSnapshot& vm_snapshot, + const DartSnapshot& isolate_snapshot); + + uintptr_t Read(uint8_t* buffer, uintptr_t length); + int64_t Seek(int64_t offset, int32_t whence); + + // The sum of all the blobs' sizes. + size_t FullSize() const; + + private: + size_t AbsoluteOffsetForIndex(BlobsIndex index); + BlobsIndex IndexForAbsoluteOffset(int64_t offset, BlobsIndex startIndex); + + BlobsIndex current_index_ = {0, 0}; + std::vector> blobs_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_SHOREBIRD_SNAPSHOTS_DATA_HANDLE_H_ diff --git a/engine/src/flutter/shell/common/shorebird/snapshots_data_handle_unittests.cc b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle_unittests.cc new file mode 100644 index 0000000000000..2acf44a7b8973 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/snapshots_data_handle_unittests.cc @@ -0,0 +1,177 @@ +#include +#include +#include + +#include "flutter/shell/common/shorebird/snapshots_data_handle.h" + +#include "flutter/fml/mapping.h" +#include "flutter/runtime/dart_snapshot.h" +#include "flutter/testing/testing.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "testing/fixture_test.h" + +namespace flutter { +namespace testing { + +std::unique_ptr MakeHandle( + std::vector& blobs) { + // Map the strings into non-owned mappings: + std::vector> mappings = {}; + for (auto& blob : blobs) { + std::unique_ptr mapping = + std::make_unique( + reinterpret_cast(blob.data()), blob.size()); + mappings.push_back(std::move(mapping)); + } + auto handle = + std::make_unique(std::move(mappings)); + return handle; +} + +TEST(SnapshotsDataHandle, Read) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 12; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + blobs_handle->Read(buffer, 6); + + EXPECT_EQ(buffer[0], 'a'); + EXPECT_EQ(buffer[1], 'b'); + EXPECT_EQ(buffer[2], 'c'); + EXPECT_EQ(buffer[3], 'd'); + EXPECT_EQ(buffer[4], 'e'); + EXPECT_EQ(buffer[5], 'f'); + + // Only the first 6 bytes should have been read. + EXPECT_EQ(buffer[6], 0); +} + +TEST(SnapshotsDataHandle, ReadAfterSeekWithPositiveOffset) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + blobs_handle->Seek(4, SEEK_CUR); + blobs_handle->Read(buffer, 6); + + EXPECT_EQ(buffer[0], 'e'); + EXPECT_EQ(buffer[1], 'f'); + EXPECT_EQ(buffer[2], 'g'); + EXPECT_EQ(buffer[3], 'h'); + EXPECT_EQ(buffer[4], 'i'); + EXPECT_EQ(buffer[5], 'j'); + + // Only the first 6 bytes should have been read. + EXPECT_EQ(buffer[6], 0); +} + +TEST(SnapshotsDataHandle, ReadAfterSeekWithNegativeOffset) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + blobs_handle->Read(buffer, 5); + EXPECT_EQ(buffer[0], 'a'); + EXPECT_EQ(buffer[1], 'b'); + EXPECT_EQ(buffer[2], 'c'); + EXPECT_EQ(buffer[3], 'd'); + EXPECT_EQ(buffer[4], 'e'); + EXPECT_EQ(buffer[5], 0); + + // Reset buffer + std::fill(buffer, buffer + buffer_size, 0); + + // Read 5, seeked back 4, should start reading at offset 1 ('b') + blobs_handle->Seek(-4, SEEK_CUR); + blobs_handle->Read(buffer, 6); + + EXPECT_EQ(buffer[0], 'b'); + EXPECT_EQ(buffer[1], 'c'); + EXPECT_EQ(buffer[2], 'd'); + EXPECT_EQ(buffer[3], 'e'); + EXPECT_EQ(buffer[4], 'f'); + EXPECT_EQ(buffer[5], 'g'); + EXPECT_EQ(buffer[6], 0); +} + +TEST(SnapshotsDataHandle, SeekPastEnd) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + // Seek 1 past the end + blobs_handle->Seek(blobs_handle->FullSize() + 1, SEEK_CUR); + + // Seek back 2 bytes and read 2 bytes + blobs_handle->Seek(-2, SEEK_CUR); + blobs_handle->Read(buffer, 2); + + EXPECT_EQ(buffer[0], 'k'); + EXPECT_EQ(buffer[1], 'l'); +} + +TEST(SnapshotsDataHandle, SeekBeforeBeginning) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + // Seek before the start of the blobs and read the first 2 bytes. + blobs_handle->Seek(-2, SEEK_CUR); + blobs_handle->Read(buffer, 2); + + EXPECT_EQ(buffer[0], 'a'); + EXPECT_EQ(buffer[1], 'b'); +} + +TEST(SnapshotsDataHandle, SeekFromBeginning) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + // Seek 10 bytes from current (the beginning) + blobs_handle->Seek(10, SEEK_CUR); + + // Seek 2 bytes from the beginning and read 2 bytes + blobs_handle->Seek(2, SEEK_SET); + blobs_handle->Read(buffer, 2); + + EXPECT_EQ(buffer[0], 'c'); + EXPECT_EQ(buffer[1], 'd'); +} + +TEST(SnapshotsDataHandle, SeekFromEnd) { + std::vector blobs = {"abc", "def", "ghi", "jkl"}; + std::unique_ptr blobs_handle = MakeHandle(blobs); + + const size_t buffer_size = 20; + uint8_t buffer[buffer_size]; + std::fill(buffer, buffer + buffer_size, 0); + + // Seek 2 bytes from the end and read 2 bytes + blobs_handle->Seek(-2, SEEK_END); + blobs_handle->Read(buffer, 2); + + EXPECT_EQ(buffer[0], 'k'); + EXPECT_EQ(buffer[1], 'l'); +} + +} // namespace testing +} // namespace flutter diff --git a/engine/src/flutter/shell/common/shorebird/updater.cc b/engine/src/flutter/shell/common/shorebird/updater.cc new file mode 100644 index 0000000000000..63d993613c3f9 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater.cc @@ -0,0 +1,202 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/shorebird/updater.h" + +#include "flutter/fml/logging.h" + +#if SHOREBIRD_PLATFORM_SUPPORTED +#include "third_party/updater/library/include/updater.h" +#endif + +namespace flutter { +namespace shorebird { + +// Static member definitions +std::unique_ptr Updater::instance_; +std::mutex Updater::instance_mutex_; +std::atomic Updater::launch_started_{false}; +std::atomic Updater::launch_completed_{false}; + +Updater& Updater::Instance() { + std::lock_guard lock(instance_mutex_); + if (!instance_) { +#if SHOREBIRD_PLATFORM_SUPPORTED + instance_ = std::make_unique(); +#else + instance_ = std::make_unique(); +#endif + } + return *instance_; +} + +void Updater::SetInstanceForTesting(std::unique_ptr instance) { + std::lock_guard lock(instance_mutex_); + instance_ = std::move(instance); +} + +void Updater::ResetInstanceForTesting() { + std::lock_guard lock(instance_mutex_); + instance_.reset(); +} + +void Updater::ResetLaunchStateForTesting() { + launch_started_.store(false); + launch_completed_.store(false); +} + +void Updater::ReportLaunchStart() { + // Guard: only the first engine in a process should promote next_boot โ†’ + // current_boot in the Rust updater. See class-level comment for rationale. + bool expected = false; + if (!launch_started_.compare_exchange_strong(expected, true)) { + return; + } + DoReportLaunchStart(); +} + +void Updater::ReportLaunchSuccess() { + // Guard: only report success once per process. Subsequent engines reuse + // the same patch and don't need to re-confirm the boot. + bool expected = false; + if (!launch_completed_.compare_exchange_strong(expected, true)) { + return; + } + DoReportLaunchSuccess(); +} + +void Updater::ReportLaunchFailure() { + // Guard: only report failure once per process. + bool expected = false; + if (!launch_completed_.compare_exchange_strong(expected, true)) { + return; + } + DoReportLaunchFailure(); +} + +#if SHOREBIRD_PLATFORM_SUPPORTED +// RealUpdater implementation - wraps the Rust C API + +bool RealUpdater::Init(const AppConfig& config) { + // Convert paths to C strings + std::vector c_paths; + c_paths.reserve(config.original_libapp_paths.size()); + for (const auto& path : config.original_libapp_paths) { + c_paths.push_back(path.c_str()); + } + + AppParameters params; + params.release_version = config.release_version.c_str(); + params.original_libapp_paths = c_paths.data(); + params.original_libapp_paths_size = static_cast(c_paths.size()); + params.app_storage_dir = config.app_storage_dir.c_str(); + params.code_cache_dir = config.code_cache_dir.c_str(); + + // Convert our FileCallbacks to the Rust struct + ::FileCallbacks rust_callbacks; + rust_callbacks.open = config.file_callbacks.open; + rust_callbacks.read = config.file_callbacks.read; + rust_callbacks.seek = config.file_callbacks.seek; + rust_callbacks.close = config.file_callbacks.close; + + return shorebird_init(¶ms, rust_callbacks, config.yaml_config.c_str()); +} + +void RealUpdater::ValidateNextBootPatch() { + shorebird_validate_next_boot_patch(); +} + +std::string RealUpdater::NextBootPatchPath() { + char* c_path = shorebird_next_boot_patch_path(); + if (c_path == nullptr) { + return ""; + } + std::string path(c_path); + shorebird_free_string(c_path); + return path; +} + +void RealUpdater::DoReportLaunchStart() { + shorebird_report_launch_start(); +} + +void RealUpdater::DoReportLaunchSuccess() { + shorebird_report_launch_success(); +} + +void RealUpdater::DoReportLaunchFailure() { + shorebird_report_launch_failure(); +} + +bool RealUpdater::ShouldAutoUpdate() { + return shorebird_should_auto_update(); +} + +void RealUpdater::StartUpdateThread() { + shorebird_start_update_thread(); +} +#endif // SHOREBIRD_PLATFORM_SUPPORTED + +// MockUpdater implementation - for testing + +bool MockUpdater::Init(const AppConfig& config) { + init_count_++; + last_release_version_ = config.release_version; + last_yaml_config_ = config.yaml_config; + call_log_.push_back("Init"); + return init_result_; +} + +void MockUpdater::ValidateNextBootPatch() { + validate_count_++; + call_log_.push_back("ValidateNextBootPatch"); +} + +std::string MockUpdater::NextBootPatchPath() { + call_log_.push_back("NextBootPatchPath"); + return next_boot_patch_path_; +} + +void MockUpdater::DoReportLaunchStart() { + launch_start_count_++; + call_log_.push_back("ReportLaunchStart"); +} + +void MockUpdater::DoReportLaunchSuccess() { + launch_success_count_++; + call_log_.push_back("ReportLaunchSuccess"); +} + +void MockUpdater::DoReportLaunchFailure() { + launch_failure_count_++; + call_log_.push_back("ReportLaunchFailure"); +} + +bool MockUpdater::ShouldAutoUpdate() { + call_log_.push_back("ShouldAutoUpdate"); + return should_auto_update_; +} + +void MockUpdater::StartUpdateThread() { + start_update_thread_count_++; + call_log_.push_back("StartUpdateThread"); +} + +void MockUpdater::Reset() { + init_count_ = 0; + validate_count_ = 0; + launch_start_count_ = 0; + launch_success_count_ = 0; + launch_failure_count_ = 0; + start_update_thread_count_ = 0; + init_result_ = true; + should_auto_update_ = false; + next_boot_patch_path_.clear(); + last_release_version_.clear(); + last_yaml_config_.clear(); + call_log_.clear(); +} + +} // namespace shorebird +} // namespace flutter diff --git a/engine/src/flutter/shell/common/shorebird/updater.h b/engine/src/flutter/shell/common/shorebird/updater.h new file mode 100644 index 0000000000000..aeb2d1f2d90cc --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater.h @@ -0,0 +1,230 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_COMMON_SHOREBIRD_UPDATER_H_ +#define FLUTTER_SHELL_COMMON_SHOREBIRD_UPDATER_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace flutter { +namespace shorebird { + +/// File callbacks for iOS patch loading. +/// Mirrors the FileCallbacks struct from the Rust updater. +struct FileCallbacks { + void* (*open)(void); + uintptr_t (*read)(void* file_handle, uint8_t* buffer, uintptr_t count); + int64_t (*seek)(void* file_handle, int64_t offset, int32_t whence); + void (*close)(void* file_handle); +}; + +/// Configuration for initializing the Shorebird updater. +struct AppConfig { + /// Version string for this release (e.g., "1.0.0+1"). + std::string release_version; + + /// Paths to the original AOT libraries (libapp.so on Android, App.framework + /// on iOS). + std::vector original_libapp_paths; + + /// Directory for persistent updater state (survives app updates). + std::string app_storage_dir; + + /// Directory for cached artifacts (cleared on app updates). + std::string code_cache_dir; + + /// Callbacks for iOS patch file access (can be null callbacks on Android). + FileCallbacks file_callbacks; + + /// YAML configuration from shorebird.yaml. + std::string yaml_config; +}; + +/// Abstract interface for the Shorebird updater. +/// +/// This abstraction allows for: +/// 1. Mocking in tests without requiring the real Rust library +/// 2. Future migration from Rust to C++ implementation +/// 3. Test instrumentation (call counting, logging) +/// +/// ## Launch lifecycle (start/success/failure) +/// +/// The Rust updater uses a start/success/failure protocol to detect crashes: +/// - `ReportLaunchStart` copies `next_boot` โ†’ `current_boot` in the Rust +/// state. If the app crashes before `ReportLaunchSuccess`, the updater +/// assumes the patch caused the crash and rolls back on the next launch. +/// +/// These calls are guarded to execute at most once per process because: +/// 1. The Rust updater is a process-global singleton โ€” calling +/// `report_launch_start` multiple times would repeatedly copy `next_boot` +/// โ†’ `current_boot`, which could promote a newly-downloaded (but not yet +/// booted) patch to "current" even though the running engine loaded the +/// old snapshot. +/// 2. In add-to-app, multiple FlutterEngines may be created and destroyed +/// within a single process. Each engine creation resolves snapshots and +/// constructs a Shell, but we must only report launch start/success once +/// โ€” for the first engine that actually boots. Without this guard, a +/// background update that completes between engine creations would get +/// promoted to "current" by the second engine's `ReportLaunchStart`, +/// even though that engine is still running the old snapshot. +/// +/// Tests can call `ResetLaunchStateForTesting()` to re-enable the guards. +class Updater { + public: + virtual ~Updater() = default; + + /// Initialize the updater with configuration. + /// @param config Configuration containing release version, paths, and + /// callbacks + /// @return true if initialization succeeded + virtual bool Init(const AppConfig& config) = 0; + + /// Validate the next boot patch. If invalid, falls back to last good state. + virtual void ValidateNextBootPatch() = 0; + + /// Get the path to the patch that will boot on next run. + /// @return Path to patch, or empty string if no patch available + virtual std::string NextBootPatchPath() = 0; + + // Boot lifecycle methods โ€” guarded to run at most once per process. + // Callers may call these freely; subsequent calls after the first are + // silently ignored. + void ReportLaunchStart(); + void ReportLaunchSuccess(); + void ReportLaunchFailure(); + + // Update checking + virtual bool ShouldAutoUpdate() = 0; + virtual void StartUpdateThread() = 0; + + // Singleton access + static Updater& Instance(); + + // Test support - allows injecting a mock implementation + static void SetInstanceForTesting(std::unique_ptr instance); + static void ResetInstanceForTesting(); + + /// Resets the once-per-process launch guards so tests can verify + /// start/success/failure calls on fresh Updater instances. + static void ResetLaunchStateForTesting(); + + protected: + Updater() = default; + + // Subclass hooks โ€” called by the public guarded methods above. + virtual void DoReportLaunchStart() = 0; + virtual void DoReportLaunchSuccess() = 0; + virtual void DoReportLaunchFailure() = 0; + + private: + static std::unique_ptr instance_; + static std::mutex instance_mutex_; + + // Once-per-process guards for launch lifecycle. + static std::atomic launch_started_; + static std::atomic launch_completed_; +}; + +/// No-op implementation for unsupported platforms. +/// All methods are safe to call but do nothing. +class NoOpUpdater : public Updater { + public: + NoOpUpdater() = default; + ~NoOpUpdater() override = default; + + bool Init(const AppConfig& config) override { return true; } + void ValidateNextBootPatch() override {} + std::string NextBootPatchPath() override { return ""; } + void DoReportLaunchStart() override {} + void DoReportLaunchSuccess() override {} + void DoReportLaunchFailure() override {} + bool ShouldAutoUpdate() override { return false; } + void StartUpdateThread() override {} +}; + +#if SHOREBIRD_PLATFORM_SUPPORTED +/// Production implementation that wraps the Rust updater C API. +/// Only available on supported platforms (Android, iOS, macOS, Windows, Linux). +class RealUpdater : public Updater { + public: + RealUpdater() = default; + ~RealUpdater() override = default; + + bool Init(const AppConfig& config) override; + void ValidateNextBootPatch() override; + std::string NextBootPatchPath() override; + void DoReportLaunchStart() override; + void DoReportLaunchSuccess() override; + void DoReportLaunchFailure() override; + bool ShouldAutoUpdate() override; + void StartUpdateThread() override; +}; +#endif // SHOREBIRD_PLATFORM_SUPPORTED + +/// Mock implementation for testing. +/// Tracks call counts and can be queried to verify behavior. +class MockUpdater : public Updater { + public: + MockUpdater() = default; + ~MockUpdater() override = default; + + bool Init(const AppConfig& config) override; + void ValidateNextBootPatch() override; + std::string NextBootPatchPath() override; + void DoReportLaunchStart() override; + void DoReportLaunchSuccess() override; + void DoReportLaunchFailure() override; + bool ShouldAutoUpdate() override; + void StartUpdateThread() override; + + // Test accessors + int init_count() const { return init_count_; } + int validate_count() const { return validate_count_; } + int launch_start_count() const { return launch_start_count_; } + int launch_success_count() const { return launch_success_count_; } + int launch_failure_count() const { return launch_failure_count_; } + int start_update_thread_count() const { return start_update_thread_count_; } + const std::vector& call_log() const { return call_log_; } + + // Last init parameters (for verification) + const std::string& last_release_version() const { + return last_release_version_; + } + const std::string& last_yaml_config() const { return last_yaml_config_; } + + // Test configuration + void set_init_result(bool value) { init_result_ = value; } + void set_should_auto_update(bool value) { should_auto_update_ = value; } + void set_next_boot_patch_path(const std::string& path) { + next_boot_patch_path_ = path; + } + + // Reset all counters and logs + void Reset(); + + private: + int init_count_ = 0; + int validate_count_ = 0; + int launch_start_count_ = 0; + int launch_success_count_ = 0; + int launch_failure_count_ = 0; + int start_update_thread_count_ = 0; + bool init_result_ = true; + bool should_auto_update_ = false; + std::string next_boot_patch_path_; + std::string last_release_version_; + std::string last_yaml_config_; + std::vector call_log_; +}; + +} // namespace shorebird +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_SHOREBIRD_UPDATER_H_ diff --git a/engine/src/flutter/shell/common/shorebird/updater_unittests.cc b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc new file mode 100644 index 0000000000000..def93050e885d --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc @@ -0,0 +1,183 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/shorebird/updater.h" + +#include "gtest/gtest.h" + +namespace flutter { +namespace shorebird { +namespace testing { + +class UpdaterTest : public ::testing::Test { + protected: + void SetUp() override { + // Install a mock for each test and reset the once-per-process guards + // so each test starts with a clean slate. + auto mock = std::make_unique(); + mock_ = mock.get(); + Updater::SetInstanceForTesting(std::move(mock)); + Updater::ResetLaunchStateForTesting(); + } + + void TearDown() override { + mock_ = nullptr; + Updater::ResetInstanceForTesting(); + Updater::ResetLaunchStateForTesting(); + } + + MockUpdater* mock_ = nullptr; +}; + +// ReportLaunchStart is guarded to run at most once per process. +// The second call should be silently ignored. +TEST_F(UpdaterTest, ReportLaunchStartOnlyCallsOnce) { + EXPECT_EQ(mock_->launch_start_count(), 0); + + Updater::Instance().ReportLaunchStart(); + EXPECT_EQ(mock_->launch_start_count(), 1); + + // Second call is a no-op due to the once-per-process guard. + Updater::Instance().ReportLaunchStart(); + EXPECT_EQ(mock_->launch_start_count(), 1); +} + +TEST_F(UpdaterTest, ReportLaunchSuccessOnlyCallsOnce) { + EXPECT_EQ(mock_->launch_success_count(), 0); + + Updater::Instance().ReportLaunchSuccess(); + EXPECT_EQ(mock_->launch_success_count(), 1); + + // Second call is a no-op. + Updater::Instance().ReportLaunchSuccess(); + EXPECT_EQ(mock_->launch_success_count(), 1); +} + +TEST_F(UpdaterTest, ReportLaunchFailureOnlyCallsOnce) { + EXPECT_EQ(mock_->launch_failure_count(), 0); + + Updater::Instance().ReportLaunchFailure(); + EXPECT_EQ(mock_->launch_failure_count(), 1); + + // Second call is a no-op. + Updater::Instance().ReportLaunchFailure(); + EXPECT_EQ(mock_->launch_failure_count(), 1); +} + +TEST_F(UpdaterTest, MockUpdaterTracksShouldAutoUpdate) { + mock_->set_should_auto_update(false); + EXPECT_FALSE(Updater::Instance().ShouldAutoUpdate()); + + mock_->set_should_auto_update(true); + EXPECT_TRUE(Updater::Instance().ShouldAutoUpdate()); +} + +TEST_F(UpdaterTest, MockUpdaterTracksStartUpdateThreadCalls) { + EXPECT_EQ(mock_->start_update_thread_count(), 0); + + Updater::Instance().StartUpdateThread(); + EXPECT_EQ(mock_->start_update_thread_count(), 1); +} + +TEST_F(UpdaterTest, MockUpdaterCallLogRecordsSequence) { + EXPECT_TRUE(mock_->call_log().empty()); + + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ShouldAutoUpdate(); + Updater::Instance().ReportLaunchSuccess(); + + const auto& log = mock_->call_log(); + ASSERT_EQ(log.size(), 3u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ShouldAutoUpdate"); + EXPECT_EQ(log[2], "ReportLaunchSuccess"); +} + +TEST_F(UpdaterTest, MockUpdaterResetClearsState) { + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + mock_->set_should_auto_update(true); + + EXPECT_EQ(mock_->launch_start_count(), 1); + EXPECT_EQ(mock_->launch_success_count(), 1); + EXPECT_TRUE(mock_->ShouldAutoUpdate()); + + mock_->Reset(); + + EXPECT_EQ(mock_->launch_start_count(), 0); + EXPECT_EQ(mock_->launch_success_count(), 0); + // Check call_log before ShouldAutoUpdate() since the method adds to call_log + EXPECT_TRUE(mock_->call_log().empty()); + EXPECT_FALSE(mock_->ShouldAutoUpdate()); +} + +// ReportLaunchStart and ReportLaunchSuccess are paired once per process. +// The Rust updater no-ops both when no patch is booting. +TEST_F(UpdaterTest, LaunchStartAndSuccessArePairedOncePerProcess) { + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + + EXPECT_EQ(mock_->launch_start_count(), 1); + EXPECT_EQ(mock_->launch_success_count(), 1); + const auto& log = mock_->call_log(); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); +} + +// ReportLaunchStart and ReportLaunchFailure are paired once per process. +TEST_F(UpdaterTest, LaunchStartAndFailureArePairedOncePerProcess) { + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchFailure(); + + EXPECT_EQ(mock_->launch_start_count(), 1); + EXPECT_EQ(mock_->launch_failure_count(), 1); + const auto& log = mock_->call_log(); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchFailure"); +} + +// Simulates the add-to-app scenario: multiple engines call ReportLaunchStart +// and ReportLaunchSuccess, but only the first should actually reach the +// updater. This prevents the Rust updater from promoting a newly-downloaded +// patch to "current_boot" when subsequent engines are still running the +// original snapshot. +TEST_F(UpdaterTest, MultipleEnginesOnlyReportOnce) { + // First engine boots. + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + + // Second engine boots โ€” these should be no-ops. + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + + EXPECT_EQ(mock_->launch_start_count(), 1); + EXPECT_EQ(mock_->launch_success_count(), 1); + + const auto& log = mock_->call_log(); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); +} + +// ResetLaunchStateForTesting re-enables the guards, allowing tests to +// verify launch calls on a fresh state. +TEST_F(UpdaterTest, ResetLaunchStateReenablesGuards) { + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + EXPECT_EQ(mock_->launch_start_count(), 1); + EXPECT_EQ(mock_->launch_success_count(), 1); + + Updater::ResetLaunchStateForTesting(); + + Updater::Instance().ReportLaunchStart(); + Updater::Instance().ReportLaunchSuccess(); + EXPECT_EQ(mock_->launch_start_count(), 2); + EXPECT_EQ(mock_->launch_success_count(), 2); +} + +} // namespace testing +} // namespace shorebird +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index 3d92422cccb3f..066e16ae09567 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -171,6 +171,7 @@ source_set("flutter_shell_native_src") { "//flutter/runtime", "//flutter/runtime:libdart", "//flutter/shell/common", + "//flutter/shell/common/shorebird", "//flutter/shell/platform/android/context", "//flutter/shell/platform/android/external_view_embedder", "//flutter/shell/platform/android/jni", @@ -797,8 +798,10 @@ if (target_cpu != "x86") { } } -if (host_os == "linux" && - (target_cpu == "x64" || target_cpu == "arm64" || target_cpu == "riscv64")) { +# Build analyze_snapshot for 64-bit target CPUs on linux. +# Or always targeting arm64 for Shorebird builds. +if ((host_os == "linux" && (target_cpu == "x64" || target_cpu == "riscv64")) || + target_cpu == "arm64") { zip_bundle("analyze_snapshot") { deps = [ "$dart_src/runtime/bin:analyze_snapshot($host_toolchain)" ] diff --git a/engine/src/flutter/shell/platform/android/android_exports.lst b/engine/src/flutter/shell/platform/android/android_exports.lst index 198bff773dd74..9b924e7738cd4 100644 --- a/engine/src/flutter/shell/platform/android/android_exports.lst +++ b/engine/src/flutter/shell/platform/android/android_exports.lst @@ -11,6 +11,18 @@ _binary_icudtl_dat_size; InternalFlutterGpu*; kInternalFlutterGpu*; + shorebird_init; + shorebird_active_path; + shorebird_active_patch_number; + shorebird_free_string; + shorebird_free_update_result; + shorebird_check_for_downloadable_update; + shorebird_check_for_update; + shorebird_update; + shorebird_update_with_result; + shorebird_next_boot_patch_number; + shorebird_current_boot_patch_number; + shorebird_validate_next_boot_patch; local: *; }; diff --git a/engine/src/flutter/shell/platform/android/flutter_main.cc b/engine/src/flutter/shell/platform/android/flutter_main.cc index d14ac40029645..45e369f5b3a9d 100644 --- a/engine/src/flutter/shell/platform/android/flutter_main.cc +++ b/engine/src/flutter/shell/platform/android/flutter_main.cc @@ -20,6 +20,7 @@ #include "flutter/fml/platform/android/paths_android.h" #include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/runtime/dart_vm.h" +#include "flutter/shell/common/shorebird/shorebird.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/platform/android/android_context_vk_impeller.h" #include "flutter/shell/platform/android/android_rendering_selector.h" @@ -93,6 +94,9 @@ void FlutterMain::Init(JNIEnv* env, jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, + jstring shorebirdYaml, + jstring version, + jstring versionCode, jlong initTimeMillis, jint api_level) { std::vector args; @@ -151,8 +155,18 @@ void FlutterMain::Init(JNIEnv* env, flutter::DartCallbackCache::SetCachePath( fml::jni::JavaStringToString(env, appStoragePath)); - fml::paths::InitializeAndroidCachesPath( - fml::jni::JavaStringToString(env, engineCachesPath)); + auto code_cache_path = fml::jni::JavaStringToString(env, engineCachesPath); + auto app_storage_path = fml::jni::JavaStringToString(env, appStoragePath); + fml::paths::InitializeAndroidCachesPath(code_cache_path); + +#if FLUTTER_RELEASE + std::string shorebird_yaml = fml::jni::JavaStringToString(env, shorebirdYaml); + std::string version_string = fml::jni::JavaStringToString(env, version); + std::string version_code_string = + fml::jni::JavaStringToString(env, versionCode); + ConfigureShorebird(code_cache_path, app_storage_path, settings, + shorebird_yaml, version_string, version_code_string); +#endif flutter::DartCallbackCache::LoadCacheFromDisk(); @@ -245,6 +259,7 @@ bool FlutterMain::Register(JNIEnv* env) { { .name = "nativeInit", .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" + "lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/" "lang/String;Ljava/lang/String;Ljava/lang/String;JI)V", .fnPtr = reinterpret_cast(&Init), }, diff --git a/engine/src/flutter/shell/platform/android/flutter_main.h b/engine/src/flutter/shell/platform/android/flutter_main.h index dda959801bc32..cf03f889ec30e 100644 --- a/engine/src/flutter/shell/platform/android/flutter_main.h +++ b/engine/src/flutter/shell/platform/android/flutter_main.h @@ -44,6 +44,9 @@ class FlutterMain { jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, + jstring shorebirdYaml, + jstring version, + jstring versionCode, jlong initTimeMillis, jint api_level); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 55542f35d6d08..b8c07e2b13d43 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -571,6 +571,7 @@ public boolean onPreDraw() { void onResume() { Log.v(TAG, "onResume()"); ensureAlive(); + flutterEngine.getRenderer().restoreSurfaceProducers(); if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) { flutterEngine.getLifecycleChannel().appIsResumed(); } diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 2f97368b6e327..30b53b75b0ada 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -8,6 +8,8 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.ColorSpace; @@ -43,7 +45,10 @@ import io.flutter.view.AccessibilityBridge; import io.flutter.view.FlutterCallbackInformation; import io.flutter.view.TextureRegistry; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -180,6 +185,9 @@ private static native void nativeInit( @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath, + @Nullable String shorebirdYaml, + @Nullable String version, + @Nullable String versionCode, long initTimeMillis, int apiLevel); @@ -208,8 +216,47 @@ public void init( Log.w(TAG, "FlutterJNI.init called more than once"); } + String version = null; + String versionCode = null; + try { + PackageInfo packageInfo = + context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + version = packageInfo.versionName; + if (Build.VERSION.SDK_INT >= API_LEVELS.API_28) { + versionCode = String.valueOf(packageInfo.getLongVersionCode()); + } else { + versionCode = String.valueOf(packageInfo.versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to read app version. Shorebird updater can't run.", e); + } + + String shorebirdYaml = null; + try { + InputStream yaml = context.getAssets().open("flutter_assets/shorebird.yaml"); + BufferedReader r = new BufferedReader(new InputStreamReader(yaml)); + StringBuilder total = new StringBuilder(); + for (String line; (line = r.readLine()) != null; ) { + total.append(line).append('\n'); + } + shorebirdYaml = total.toString(); + Log.d(TAG, "shorebird.yaml: " + shorebirdYaml); + } catch (IOException e) { + Log.e(TAG, "Failed to load shorebird.yaml", e); + Log.e(TAG, "Did you remember to include shorebird.yaml in your pubspec.yaml's assets?"); + } + FlutterJNI.nativeInit( - context, args, bundlePath, appStoragePath, engineCachesPath, initTimeMillis, apiLevel); + context, + args, + bundlePath, + appStoragePath, + engineCachesPath, + shorebirdYaml, + version, + versionCode, + initTimeMillis, + apiLevel); FlutterJNI.initCalled = true; } diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index 929b3c76f5392..a4cbe046cf59f 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -24,9 +24,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; -import androidx.lifecycle.DefaultLifecycleObserver; -import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.ProcessLifecycleOwner; import io.flutter.Log; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.view.TextureRegistry; @@ -100,21 +97,23 @@ public void onFlutterUiNoLongerDisplayed() { public FlutterRenderer(@NonNull FlutterJNI flutterJNI) { this.flutterJNI = flutterJNI; this.flutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener); - ProcessLifecycleOwner.get() - .getLifecycle() - .addObserver( - new DefaultLifecycleObserver() { - @Override - public void onResume(@NonNull LifecycleOwner owner) { - Log.v(TAG, "onResume called; notifying SurfaceProducers"); - for (ImageReaderSurfaceProducer producer : imageReaderProducers) { - if (producer.callback != null && producer.notifiedDestroy) { - producer.notifiedDestroy = false; - producer.callback.onSurfaceAvailable(); - } - } - } - }); + } + + /** + * Restores {@code ImageReaderSurfaceProducer}s that were previously notified to be destroyed due + * to a call to {@code onTrimMemory} as part of an {@code onResume} app lifecycle event. + * + *

All {@code FlutterActivity}s and {@code FlutterFragment}s are expected to call this {@code + * onResume} to ensure surface producers are restored when the app returns to the foreground. + */ + public void restoreSurfaceProducers() { + Log.v(TAG, "restoreSurfaceProducers called; notifying SurfaceProducers"); + for (ImageReaderSurfaceProducer producer : imageReaderProducers) { + if (producer.callback != null && producer.notifiedDestroy) { + producer.notifiedDestroy = false; + producer.callback.onSurfaceAvailable(); + } + } } /** @@ -452,7 +451,7 @@ final class ImageReaderSurfaceProducer * *

Used to avoid signaling {@link Callback#onSurfaceAvailable()} unnecessarily. */ - private boolean notifiedDestroy = false; + @VisibleForTesting boolean notifiedDestroy = false; // State held to track latency of various stages. private long lastDequeueTime = 0; @@ -466,7 +465,8 @@ final class ImageReaderSurfaceProducer private final HashMap perImageReaders = new HashMap<>(); private ArrayList lastDequeuedImage = new ArrayList(); private PerImageReader lastReaderDequeuedFrom = null; - private Callback callback = null; + + @VisibleForTesting Callback callback = null; /** Internal class: state held per Image produced by ImageReaders. */ private class PerImage { diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java index def3e430b038f..9aded3ece74fa 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -1083,12 +1083,13 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { // // See the case above for how virtual displays are handled. if (!platformViewsAccessibilityDelegate.usesVirtualDisplay(child.platformViewId)) { - assert embeddedView != null; - // The embedded view is initially marked as not important at creation in the platform - // view controller, so we must explicitly mark it as important here. - embeddedView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); - result.addChild(embeddedView); - continue; + if (embeddedView != null) { + // The embedded view is initially marked as not important at creation in the platform + // view controller, so we must explicitly mark it as important here. + embeddedView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); + result.addChild(embeddedView); + continue; + } } } result.addChild(rootAccessibilityView, child.id); diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 7728ffb4180b7..ca2e40d1b96bc 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -1614,6 +1614,16 @@ public void itDoesNotDetachTwice() { } } + @Test + public void onResume_restoresSurfaceProducers() { + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + delegate.onAttach(ctx); + delegate.onResume(); + + verify(mockFlutterEngine.getRenderer()).restoreSurfaceProducers(); + } + /** * Creates a mock {@link io.flutter.embedding.engine.FlutterEngine}. * diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java index d08a31be6fcf3..8b6262e0ff5af 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java @@ -32,9 +32,6 @@ import android.media.ImageReader; import android.os.Looper; import android.view.Surface; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleRegistry; -import androidx.lifecycle.ProcessLifecycleOwner; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import io.flutter.embedding.android.FlutterActivity; @@ -924,38 +921,6 @@ public void ImageReaderSurfaceProducerUnsubscribesWhenReleased() { verify(callback, never()).onSurfaceDestroyed(); } - @Test - @SuppressWarnings({"deprecation", "removal"}) - public void ImageReaderSurfaceProducerIsCreatedOnLifecycleResume() throws Exception { - FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); - TextureRegistry.SurfaceProducer producer = - flutterRenderer.createSurfaceProducer(TextureRegistry.SurfaceLifecycle.resetInBackground); - - // Create a callback. - CountDownLatch latch = new CountDownLatch(1); - TextureRegistry.SurfaceProducer.Callback callback = - new TextureRegistry.SurfaceProducer.Callback() { - @Override - public void onSurfaceAvailable() { - latch.countDown(); - } - - @Override - public void onSurfaceDestroyed() {} - }; - producer.setCallback(callback); - - // Trim memory. - flutterRenderer.onTrimMemory(TRIM_MEMORY_BACKGROUND); - - // Trigger a resume. - ((LifecycleRegistry) ProcessLifecycleOwner.get().getLifecycle()) - .setCurrentState(Lifecycle.State.RESUMED); - - // Verify. - latch.await(); - } - @Test public void ImageReaderSurfaceProducerSchedulesFrameIfQueueNotEmpty() throws Exception { FlutterRenderer flutterRenderer = spy(engineRule.getFlutterEngine().getRenderer()); @@ -1062,4 +1027,24 @@ public void getSurface_doesNotReturnNewSurface() { assertEquals(firstSurface, secondSurface); } + + @Test + public void restoreSurfaceProducers_restoresImageReaderSurfaceProducersAsIfApplicationResumed() { + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + FlutterRenderer.ImageReaderSurfaceProducer imageReaderProducer1 = + (FlutterRenderer.ImageReaderSurfaceProducer) flutterRenderer.createSurfaceProducer(); + FlutterRenderer.ImageReaderSurfaceProducer imageReaderProducer2 = + (FlutterRenderer.ImageReaderSurfaceProducer) flutterRenderer.createSurfaceProducer(); + imageReaderProducer1.callback = mock(TextureRegistry.SurfaceProducer.Callback.class); + imageReaderProducer2.callback = mock(TextureRegistry.SurfaceProducer.Callback.class); + imageReaderProducer1.notifiedDestroy = true; + imageReaderProducer2.notifiedDestroy = true; + + flutterRenderer.restoreSurfaceProducers(); + + verify(imageReaderProducer1.callback).onSurfaceAvailable(); + verify(imageReaderProducer2.callback).onSurfaceAvailable(); + assertFalse(imageReaderProducer1.notifiedDestroy); + assertFalse(imageReaderProducer2.notifiedDestroy); + } } diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 5adc1d11d60f4..782e0593d0dbe 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -2061,6 +2061,46 @@ public void itProducesPlatformViewNodeForVirtualDisplay() { verify(accessibilityViewEmbedder).getRootNode(eq(embeddedView), eq(0), any(Rect.class)); } + @Test + public void itDoesNotCrashWhenEmbeddedViewIsNull() { + PlatformViewsAccessibilityDelegate accessibilityDelegate = + mock(PlatformViewsAccessibilityDelegate.class); + AccessibilityViewEmbedder accessibilityViewEmbedder = mock(AccessibilityViewEmbedder.class); + AccessibilityBridge accessibilityBridge = + setUpBridge( + /* rootAccessibilityView= */ null, + /* accessibilityChannel= */ null, + /* accessibilityManager= */ null, + /* contentResolver= */ null, + accessibilityViewEmbedder, + accessibilityDelegate); + + TestSemanticsNode root = new TestSemanticsNode(); + root.id = 0; + + TestSemanticsNode platformView = new TestSemanticsNode(); + platformView.id = 1; + platformView.platformViewId = 1; + root.addChild(platformView); + + when(accessibilityDelegate.usesVirtualDisplay(1)).thenReturn(false); + when(accessibilityDelegate.getPlatformViewById(1)).thenReturn(null); + + TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); + testSemanticsUpdate.sendUpdateToBridge(accessibilityBridge); + + // This should not crash. + AccessibilityNodeInfo result = accessibilityBridge.createAccessibilityNodeInfo(0); + + // Verify that we fell back to adding the child as a virtual node (standard semantics node) + // instead of trying to add the null embedded view. + boolean hasChild = false; + for (int i = 0; i < result.getChildCount(); i++) { + hasChild = true; + } + assertTrue("Should have added the virtual child node", hasChild); + } + @Test public void testItSetsDisableAnimationsFlagBasedOnTransitionAnimationScale() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index 911ee431e2516..777b6ae4a64bb 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -194,12 +194,14 @@ source_set("flutter_framework_source") { deps = [ ":ios_gpu_configuration", + "$dart_src/runtime/bin:elf_loader", "//flutter/common", "//flutter/common/graphics", "//flutter/fml", "//flutter/lib/ui", "//flutter/runtime", "//flutter/shell/common", + "//flutter/shell/common/shorebird", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/darwin/common", "//flutter/shell/platform/darwin/common:framework_common", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index 31a49a856a4a5..45660d1cd637d 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -13,6 +13,8 @@ #include "flutter/common/constants.h" #include "flutter/fml/build_config.h" +#include "flutter/fml/paths.h" +#include "flutter/shell/common/shorebird/shorebird.h" #include "flutter/shell/common/switches.h" #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h" #include "flutter/shell/platform/darwin/common/command_line.h" @@ -92,10 +94,12 @@ static BOOL DoesHardwareSupportWideGamut() { } if (flutter::DartVM::IsRunningPrecompiledCode()) { + NSLog(@"SANITY CHECK: Running precompiled code."); if (hasExplicitBundle) { NSString* executablePath = bundle.executablePath; if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) { settings.application_library_paths.push_back(executablePath.UTF8String); + NSLog(@"Using precompiled library from %@", executablePath); } } @@ -107,6 +111,7 @@ static BOOL DoesHardwareSupportWideGamut() { NSString* executablePath = [NSBundle bundleWithPath:libraryPath].executablePath; if (executablePath.length > 0) { settings.application_library_paths.push_back(executablePath.UTF8String); + NSLog(@"Using library from %@", libraryPath); } } } @@ -121,6 +126,7 @@ static BOOL DoesHardwareSupportWideGamut() { [NSBundle bundleWithPath:applicationFrameworkPath].executablePath; if (executablePath.length > 0) { settings.application_library_paths.push_back(executablePath.UTF8String); + NSLog(@"Using App.framework from %@", applicationFrameworkPath); } } } @@ -152,6 +158,33 @@ static BOOL DoesHardwareSupportWideGamut() { } } + NSString* assetsPath = [NSString stringWithUTF8String:settings.assets_path.c_str()]; + NSLog(@"ASSET PATH %@", assetsPath); + + // FIXME: This may not be the correct path (e.g., should it include the organization id?) + // See + // https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW13 + // /private/var/mobile/Containers/Data/Application/264477BF-6E38-47C9-AAD9-532BB842F197/Library/Application + // Support/shorebird/shorebird_updater + std::string cache_path = + fml::paths::JoinPaths({getenv("HOME"), "Library/Application Support/shorebird"}); + NSURL* shorebirdYamlPath = [NSURL URLWithString:@"shorebird.yaml" + relativeToURL:[NSURL fileURLWithPath:assetsPath]]; + NSString* appVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + NSString* appBuildNumber = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + NSString* shorebirdYamlContents = [NSString stringWithContentsOfURL:shorebirdYamlPath + encoding:NSUTF8StringEncoding + error:nil]; + if (shorebirdYamlContents != nil) { + // Note: we intentionally pass cache_path twice. We provide two different directories + // to ConfigureShorebird because Android differentiates between data that persists + // between releases and data that does not. iOS does not make this distinction. + flutter::ConfigureShorebird(cache_path, cache_path, settings, shorebirdYamlContents.UTF8String, + appVersion.UTF8String, appBuildNumber.UTF8String); + } else { + NSLog(@"Failed to find shorebird.yaml, not starting updater."); + } + // Domain network configuration // Disabled in https://github.com/flutter/flutter/issues/72723. // Re-enable in https://github.com/flutter/flutter/issues/54448. diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index d88b9bb548bad..7a97c7cf5fd92 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -573,6 +573,39 @@ - (BOOL)containsWebView:(UIView*)view remainingSubviewDepth:(int)remainingSubvie return NO; } +- (void)searchAndFixWebView:(UIView*)view { + if ([view isKindOfClass:[WKWebView class]]) { + return [self searchAndFixWebViewGestureRecognzier:view]; + } else { + for (UIView* subview in view.subviews) { + [self searchAndFixWebView:subview]; + } + } +} + +- (void)searchAndFixWebViewGestureRecognzier:(UIView*)view { + for (UIGestureRecognizer* recognizer in view.gestureRecognizers) { + // This is to fix a bug on iOS 26 where web view link is not tappable. + // We reset the web view's WKTouchEventsGestureRecognizer in a bad state + // by disabling and re-enabling it. + // See: https://github.com/flutter/flutter/issues/175099. + // See also: https://github.com/flutter/engine/pull/56804 for an explanation of the + // bug on iOS 18.2, which is still valid on iOS 26. + // Warning: This is just a quick fix that patches the bug. For example, + // touches on a drawing website is still not completely blocked. A proper solution + // should rely on overriding the hitTest behavior. + // See: https://github.com/flutter/flutter/issues/179916. + if (recognizer.enabled && + [NSStringFromClass([recognizer class]) hasSuffix:@"TouchEventsGestureRecognizer"]) { + recognizer.enabled = NO; + recognizer.enabled = YES; + } + } + for (UIView* subview in view.subviews) { + [self searchAndFixWebViewGestureRecognzier:subview]; + } +} + - (void)blockGesture { switch (_blockingPolicy) { case FlutterPlatformViewGestureRecognizersBlockingPolicyEager: @@ -588,9 +621,15 @@ - (void)blockGesture { // FlutterPlatformViewGestureRecognizersBlockingPolicyEager, but we should try it if a similar // issue arises for the other policy. if (@available(iOS 26.0, *)) { - // This workaround does not work on iOS 26. - // TODO(hellohuanlin): find a solution for iOS 26, - // https://github.com/flutter/flutter/issues/175099. + // This performs a nested DFS, with the outer one searching for any web view, and the inner + // one searching for a TouchEventsGestureRecognizer inside the web view. Once found, disable + // and immediately reenable it to reset its state. + // TODO(hellohuanlin): remove this flag after it is battle tested. + NSNumber* isWorkaroundDisabled = + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTDisableWebViewGestureReset"]; + if (!isWorkaroundDisabled.boolValue) { + [self searchAndFixWebView:self.embeddedView]; + } } else if (@available(iOS 18.2, *)) { // This workaround is designed for WKWebView only. The 1P web view plugin provides a // WKWebView itself as the platform view. However, some 3P plugins provide wrappers of diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 20b4e2936c8d9..5be853d7c7258 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -47,6 +47,36 @@ - (void)dealloc { @end +// A mock recognizer without "TouchEventsGestureRecognizer" suffix in class name. +// This is to verify a fix to a bug on iOS 26 where web view link is not tappable. +// We reset the web view's WKTouchEventsGestureRecognizer in a bad state +// by disabling and re-enabling it. +// See: https://github.com/flutter/flutter/issues/175099. +@interface MockGestureRecognizer : UIGestureRecognizer +@property(nonatomic, strong) NSMutableArray* toggleHistory; +@end + +@implementation MockGestureRecognizer +- (instancetype)init { + self = [super init]; + if (self) { + _toggleHistory = [NSMutableArray array]; + } + return self; +} +- (void)setEnabled:(BOOL)enabled { + [super setEnabled:enabled]; + [self.toggleHistory addObject:@(enabled)]; +} +@end + +// A mock recognizer with "TouchEventsGestureRecognizer" suffix in class name. +@interface MockTouchEventsGestureRecognizer : MockGestureRecognizer +@end + +@implementation MockTouchEventsGestureRecognizer +@end + @interface FlutterPlatformViewsTestMockFlutterPlatformView : NSObject @property(nonatomic, strong) UIView* view; @property(nonatomic, assign) BOOL viewCreated; @@ -3403,6 +3433,429 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], forwardingRecognizer); } +- (void) + testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldDisableAndReEnableTouchEventsGestureRecognizerForSimpleWebView { + if (@available(iOS 26.0, *)) { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kMetal, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners, + /*worker_task_runner=*/nil, + /*is_gpu_disabled_jsync_switch=*/std::make_shared()); + + FlutterPlatformViewsTestMockWebViewFactory* factory = + [[FlutterPlatformViewsTestMockWebViewFactory alloc] init]; + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockWebView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; + FlutterResult result = ^(id result) { + }; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockWebView"}] + result:result]; + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + /* + Simple Web View at root, with [*] indicating views containing + MockTouchEventsGestureRecognizer. + + Root (Web View) [*] + โ”œโ”€โ”€ Child 1 + โ””โ”€โ”€ Child 2 + โ”œโ”€โ”€ Child 2.1 + โ””โ”€โ”€ Child 2.2 [*] + */ + + UIView* root = gMockPlatformView; + root.gestureRecognizers = nil; + for (UIView* subview in root.subviews) { + [subview removeFromSuperview]; + } + + MockGestureRecognizer* normalRecognizer0 = [[MockGestureRecognizer alloc] init]; + [root addGestureRecognizer:normalRecognizer0]; + + UIView* child1 = [[UIView alloc] init]; + [root addSubview:child1]; + MockGestureRecognizer* normalRecognizer1 = [[MockGestureRecognizer alloc] init]; + [child1 addGestureRecognizer:normalRecognizer1]; + + UIView* child2 = [[UIView alloc] init]; + [root addSubview:child2]; + MockGestureRecognizer* normalRecognizer2 = [[MockGestureRecognizer alloc] init]; + [child2 addGestureRecognizer:normalRecognizer2]; + + UIView* child2_1 = [[UIView alloc] init]; + [child2 addSubview:child2_1]; + MockGestureRecognizer* normalRecognizer2_1 = [[MockGestureRecognizer alloc] init]; + [child2_1 addGestureRecognizer:normalRecognizer2_1]; + + UIView* child2_2 = [[UIView alloc] init]; + [child2 addSubview:child2_2]; + MockGestureRecognizer* normalRecognizer2_2 = [[MockGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:normalRecognizer2_2]; + + // Add the target recognizer at root & child2_2. + MockTouchEventsGestureRecognizer* targetRecognizer0 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [root addGestureRecognizer:targetRecognizer0]; + + MockTouchEventsGestureRecognizer* targetRecognizer2_2 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:targetRecognizer2_2]; + + [(FlutterTouchInterceptingView*)touchInteceptorView blockGesture]; + + NSArray* normalRecognizers = @[ + normalRecognizer0, normalRecognizer1, normalRecognizer2, normalRecognizer2_1, + normalRecognizer2_2 + ]; + + NSArray* targetRecognizers = @[ targetRecognizer0, targetRecognizer2_2 ]; + + NSArray* expectedEmptyHistory = @[]; + NSArray* expectedToggledHistory = @[ @NO, @YES ]; + + for (MockGestureRecognizer* recognizer in normalRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedEmptyHistory); + } + for (MockGestureRecognizer* recognizer in targetRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedToggledHistory); + } + } +} + +- (void) + testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldDisableAndReEnableTouchEventsGestureRecognizerForMultipleWebViewInDifferentBranches { + if (@available(iOS 26.0, *)) { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kMetal, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners, + /*worker_task_runner=*/nil, + /*is_gpu_disabled_jsync_switch=*/std::make_shared()); + + FlutterPlatformViewsTestMockWrapperWebViewFactory* factory = + [[FlutterPlatformViewsTestMockWrapperWebViewFactory alloc] init]; + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockWrapperWebView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; + FlutterResult result = ^(id result) { + }; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockWrapperWebView" + }] + result:result]; + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + /* + Platform View with Multiple Web Views in different branches, with [*] indicating views + containing MockTouchEventsGestureRecognizer. + + Root (Platform View) + โ”œโ”€โ”€ Child 1 + โ”œโ”€โ”€ Child 2 (Web View) + | โ”œโ”€โ”€ Child 2.1 + | โ””โ”€โ”€ Child 2.2 [*] + โ””โ”€โ”€ Child 3 + โ””โ”€โ”€ Child 3.1 (Web View) + โ”œโ”€โ”€ Child 3.1.1 + โ””โ”€โ”€ Child 3.1.2 [*] + */ + + UIView* root = gMockPlatformView; + for (UIView* subview in root.subviews) { + [subview removeFromSuperview]; + } + + MockGestureRecognizer* normalRecognizer0 = [[MockGestureRecognizer alloc] init]; + [root addGestureRecognizer:normalRecognizer0]; + + UIView* child1 = [[UIView alloc] init]; + [root addSubview:child1]; + MockGestureRecognizer* normalRecognizer1 = [[MockGestureRecognizer alloc] init]; + [child1 addGestureRecognizer:normalRecognizer1]; + + UIView* child2 = [[WKWebView alloc] init]; + child2.gestureRecognizers = nil; + for (UIView* subview in child2.subviews) { + [subview removeFromSuperview]; + } + [root addSubview:child2]; + MockGestureRecognizer* normalRecognizer2 = [[MockGestureRecognizer alloc] init]; + [child2 addGestureRecognizer:normalRecognizer2]; + + UIView* child2_1 = [[UIView alloc] init]; + [child2 addSubview:child2_1]; + MockGestureRecognizer* normalRecognizer2_1 = [[MockGestureRecognizer alloc] init]; + [child2_1 addGestureRecognizer:normalRecognizer2_1]; + + UIView* child2_2 = [[UIView alloc] init]; + [child2 addSubview:child2_2]; + MockGestureRecognizer* normalRecognizer2_2 = [[MockGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:normalRecognizer2_2]; + + UIView* child3 = [[UIView alloc] init]; + [root addSubview:child3]; + MockGestureRecognizer* normalRecognizer3 = [[MockGestureRecognizer alloc] init]; + [child3 addGestureRecognizer:normalRecognizer3]; + + UIView* child3_1 = [[WKWebView alloc] init]; + child3_1.gestureRecognizers = nil; + for (UIView* subview in child3_1.subviews) { + [subview removeFromSuperview]; + } + [child3 addSubview:child3_1]; + MockGestureRecognizer* normalRecognizer3_1 = [[MockGestureRecognizer alloc] init]; + [child3_1 addGestureRecognizer:normalRecognizer3_1]; + + UIView* child3_1_1 = [[UIView alloc] init]; + [child3_1 addSubview:child3_1_1]; + MockGestureRecognizer* normalRecognizer3_1_1 = [[MockGestureRecognizer alloc] init]; + [child3_1_1 addGestureRecognizer:normalRecognizer3_1_1]; + + UIView* child3_1_2 = [[UIView alloc] init]; + [child3_1 addSubview:child3_1_2]; + MockGestureRecognizer* normalRecognizer3_1_2 = [[MockGestureRecognizer alloc] init]; + [child3_1_2 addGestureRecognizer:normalRecognizer3_1_2]; + + // Add the target recognizer at child2_2 & child3_1_2 + + MockTouchEventsGestureRecognizer* targetRecognizer2_2 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:targetRecognizer2_2]; + + MockTouchEventsGestureRecognizer* targetRecognizer3_1_2 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [child3_1_2 addGestureRecognizer:targetRecognizer3_1_2]; + + [(FlutterTouchInterceptingView*)touchInteceptorView blockGesture]; + + NSArray* normalRecognizers = @[ + normalRecognizer0, normalRecognizer1, normalRecognizer2, normalRecognizer2_1, + normalRecognizer2_2, normalRecognizer3, normalRecognizer3_1, normalRecognizer3_1_1, + normalRecognizer3_1_2 + ]; + NSArray* targetRecognizers = @[ targetRecognizer2_2, targetRecognizer3_1_2 ]; + + NSArray* expectedEmptyHistory = @[]; + NSArray* expectedToggledHistory = @[ @NO, @YES ]; + + for (MockGestureRecognizer* recognizer in normalRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedEmptyHistory); + } + + for (MockGestureRecognizer* recognizer in targetRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedToggledHistory); + } + } +} + +- (void) + testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldDisableAndReEnableTouchEventsGestureRecognizerForNestedMultipleWebView { + if (@available(iOS 26.0, *)) { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kMetal, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners, + /*worker_task_runner=*/nil, + /*is_gpu_disabled_jsync_switch=*/std::make_shared()); + + FlutterPlatformViewsTestMockWebViewFactory* factory = + [[FlutterPlatformViewsTestMockWebViewFactory alloc] init]; + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockWebView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; + FlutterResult result = ^(id result) { + }; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockWebView"}] + result:result]; + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + /* + Platform View with nested web views, with [*] indicating views containing + MockTouchEventsGestureRecognizer. + + Root (Web View) + โ”œโ”€โ”€ Child 1 + โ”œโ”€โ”€ Child 2 + | โ”œโ”€โ”€ Child 2.1 + | โ””โ”€โ”€ Child 2.2 [*] + โ””โ”€โ”€ Child 3 + โ””โ”€โ”€ Child 3.1 (Another Web View) + โ””โ”€โ”€ Child 3.1.1 + โ””โ”€โ”€ Child 3.1.2 + โ”œโ”€โ”€ Child 3.1.2.1 + โ””โ”€โ”€ Child 3.1.2.2 [*] + */ + + UIView* root = gMockPlatformView; + root.gestureRecognizers = nil; + for (UIView* subview in root.subviews) { + [subview removeFromSuperview]; + } + + MockGestureRecognizer* normalRecognizer0 = [[MockGestureRecognizer alloc] init]; + [root addGestureRecognizer:normalRecognizer0]; + + UIView* child1 = [[UIView alloc] init]; + [root addSubview:child1]; + MockGestureRecognizer* normalRecognizer1 = [[MockGestureRecognizer alloc] init]; + [child1 addGestureRecognizer:normalRecognizer1]; + + UIView* child2 = [[UIView alloc] init]; + [root addSubview:child2]; + MockGestureRecognizer* normalRecognizer2 = [[MockGestureRecognizer alloc] init]; + [child2 addGestureRecognizer:normalRecognizer2]; + + UIView* child2_1 = [[UIView alloc] init]; + [child2 addSubview:child2_1]; + MockGestureRecognizer* normalRecognizer2_1 = [[MockGestureRecognizer alloc] init]; + [child2_1 addGestureRecognizer:normalRecognizer2_1]; + + UIView* child2_2 = [[UIView alloc] init]; + [child2 addSubview:child2_2]; + MockGestureRecognizer* normalRecognizer2_2 = [[MockGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:normalRecognizer2_2]; + + UIView* child3 = [[UIView alloc] init]; + [root addSubview:child3]; + MockGestureRecognizer* normalRecognizer3 = [[MockGestureRecognizer alloc] init]; + [child3 addGestureRecognizer:normalRecognizer3]; + + UIView* child3_1 = [[WKWebView alloc] init]; + child3_1.gestureRecognizers = nil; + for (UIView* subview in child3_1.subviews) { + [subview removeFromSuperview]; + } + [child3 addSubview:child3_1]; + MockGestureRecognizer* normalRecognizer3_1 = [[MockGestureRecognizer alloc] init]; + [child3_1 addGestureRecognizer:normalRecognizer3_1]; + + UIView* child3_1_1 = [[UIView alloc] init]; + [child3_1 addSubview:child3_1_1]; + MockGestureRecognizer* normalRecognizer3_1_1 = [[MockGestureRecognizer alloc] init]; + [child3_1_1 addGestureRecognizer:normalRecognizer3_1_1]; + + UIView* child3_1_2 = [[UIView alloc] init]; + [child3_1 addSubview:child3_1_2]; + MockGestureRecognizer* normalRecognizer3_1_2 = [[MockGestureRecognizer alloc] init]; + [child3_1_2 addGestureRecognizer:normalRecognizer3_1_2]; + + UIView* child3_1_2_1 = [[UIView alloc] init]; + [child3_1_2 addSubview:child3_1_2_1]; + MockGestureRecognizer* normalRecognizer3_1_2_1 = [[MockGestureRecognizer alloc] init]; + [child3_1_2_1 addGestureRecognizer:normalRecognizer3_1_2_1]; + + UIView* child3_1_2_2 = [[UIView alloc] init]; + [child3_1_2 addSubview:child3_1_2_2]; + MockGestureRecognizer* normalRecognizer3_1_2_2 = [[MockGestureRecognizer alloc] init]; + [child3_1_2_2 addGestureRecognizer:normalRecognizer3_1_2_2]; + + // Add the target recognizer at child2_2 & child3_1_2_2 + + MockTouchEventsGestureRecognizer* targetRecognizer2_2 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [child2_2 addGestureRecognizer:targetRecognizer2_2]; + + MockTouchEventsGestureRecognizer* targetRecognizer3_1_2_2 = + [[MockTouchEventsGestureRecognizer alloc] init]; + [child3_1_2_2 addGestureRecognizer:targetRecognizer3_1_2_2]; + + [(FlutterTouchInterceptingView*)touchInteceptorView blockGesture]; + + NSArray* normalRecognizers = @[ + normalRecognizer0, normalRecognizer1, normalRecognizer2, normalRecognizer2_1, + normalRecognizer2_2, normalRecognizer3, normalRecognizer3_1, normalRecognizer3_1_1, + normalRecognizer3_1_2, normalRecognizer3_1_2_1, normalRecognizer3_1_2_2 + ]; + + NSArray* targetRecognizers = @[ targetRecognizer2_2, targetRecognizer3_1_2_2 ]; + + NSArray* expectedEmptyHistory = @[]; + NSArray* expectedToggledHistory = @[ @NO, @YES ]; + + for (MockGestureRecognizer* recognizer in normalRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedEmptyHistory); + } + + for (MockGestureRecognizer* recognizer in targetRecognizers) { + XCTAssertEqualObjects(recognizer.toggleHistory, expectedToggledHistory); + } + } +} + - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing { flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 371611319d991..d20c27fe19237 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -39,6 +39,7 @@ #import "flutter/third_party/spring_animation/spring_animation.h" FLUTTER_ASSERT_ARC +#import static constexpr int kMicrosecondsPerSecond = 1000 * 1000; static constexpr CGFloat kScrollViewContentSize = 2.0; diff --git a/engine/src/flutter/shell/platform/darwin/macos/BUILD.gn b/engine/src/flutter/shell/platform/darwin/macos/BUILD.gn index bc69c85f797a0..6c5e1f4eb928b 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/macos/BUILD.gn @@ -144,12 +144,14 @@ source_set("flutter_framework_source") { ":macos_gpu_configuration", "//flutter/flow", "//flutter/fml", + "//flutter/shell/common/shorebird", "//flutter/shell/platform/common:common_cpp_accessibility", "//flutter/shell/platform/common:common_cpp_core", "//flutter/shell/platform/common:common_cpp_enums", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_isolate_scope", "//flutter/shell/platform/common:common_cpp_switches", + "//flutter/shell/platform/darwin/common", "//flutter/shell/platform/darwin/common:availability_version_check", "//flutter/shell/platform/darwin/common:framework_common", "//flutter/shell/platform/darwin/graphics", diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 8ba35a05761e3..a514611719a56 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -11,6 +11,8 @@ #include #include "flutter/common/constants.h" +#include "flutter/fml/paths.h" +#include "flutter/shell/common/shorebird/shorebird.h" #include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" @@ -656,6 +658,40 @@ - (void)onFocusChangeRequest:(const FlutterViewFocusChangeRequest*)request { } } +- (BOOL)configureShorebird:(NSString**)patchPath { + NSLog(@"[shorebird] setting up non-linker shorebird"); + NSString* bundlePath = + [[NSBundle bundleWithURL:[NSBundle.mainBundle.privateFrameworksURL + URLByAppendingPathComponent:@"App.framework"]] bundlePath]; + bundlePath = [bundlePath stringByAppendingString:@"/App"]; + NSString* assetsPath = _project.assetsPath; + NSURL* shorebirdYamlPath = [NSURL URLWithString:@"shorebird.yaml" + relativeToURL:[NSURL fileURLWithPath:assetsPath]]; + NSString* shorebirdYamlContents = [NSString stringWithContentsOfURL:shorebirdYamlPath + encoding:NSUTF8StringEncoding + error:nil]; + NSString* appVersion = + [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + NSString* appBuildNumber = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + std::string cache_path = + fml::paths::JoinPaths({getenv("HOME"), "Library", "Application Support", "shorebird"}); + flutter::ReleaseVersion release_version = {appVersion.UTF8String, appBuildNumber.UTF8String}; + flutter::ShorebirdConfigArgs shorebird_args(cache_path, cache_path, bundlePath.UTF8String, + shorebirdYamlContents.UTF8String, release_version); + NSLog(@"[shorebird] calling ConfigureShorebird"); + std::string patch_path; + auto res = flutter::ConfigureShorebird(shorebird_args, patch_path); + if (!res) { + NSLog(@"[shorebird] ConfigureShorebird failed"); + return NO; + } + + NSLog(@"[shorebird] ConfigureShorebird success!"); + *patchPath = [NSString stringWithUTF8String:patch_path.c_str()]; + NSLog(@"[shorebird] patchPath: %@", *patchPath); + return YES; +} + - (BOOL)runWithEntrypoint:(NSString*)entrypoint { if (self.running) { return NO; @@ -753,7 +789,19 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { }; flutterArguments.custom_task_runners = &custom_task_runners; - [self loadAOTData:_project.assetsPath]; + NSString* elfPath; + BOOL configureShorebirdRes = [self configureShorebird:&elfPath]; + if (!configureShorebirdRes) { + // No patch exists, or we failed to configure shorebird. This is a fallback. + // Upstream, this code lives in -(void)loadAOTData:. + // + // This is the location where the test fixture places the snapshot file. + // For applications built by Flutter tool, this is in "App.framework". + elfPath = [NSString pathWithComponents:@[ _project.assetsPath, @"app_elf_snapshot.so" ]]; + } + + [self loadAOTData:elfPath]; + if (_aotData) { flutterArguments.aot_data = _aotData; } @@ -777,6 +825,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { }; FlutterRendererConfig rendererConfig = [_renderer createRendererConfig]; + FlutterEngineResult result = _embedderAPI.Initialize( FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine); if (result != kSuccess) { @@ -806,7 +855,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { return YES; } -- (void)loadAOTData:(NSString*)assetsDir { +- (void)loadAOTData:(NSString*)elfPath { if (!_embedderAPI.RunsAOTCompiledDartCode()) { return; } @@ -814,11 +863,8 @@ - (void)loadAOTData:(NSString*)assetsDir { BOOL isDirOut = false; // required for NSFileManager fileExistsAtPath. NSFileManager* fileManager = [NSFileManager defaultManager]; - // This is the location where the test fixture places the snapshot file. - // For applications built by Flutter tool, this is in "App.framework". - NSString* elfPath = [NSString pathWithComponents:@[ assetsDir, @"app_elf_snapshot.so" ]]; - if (![fileManager fileExistsAtPath:elfPath isDirectory:&isDirOut]) { + FML_LOG(INFO) << "in loadAOTData, elfPath does not exist: " << elfPath.UTF8String; return; } diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm index 969a4db69f902..4b8eb82368488 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm @@ -781,7 +781,10 @@ - (void)insertText:(id)string replacementRange:(NSRange)range { flutter::TextRange replacedRange(-1, -1); std::string textBeforeChange = _activeModel->GetText().c_str(); - std::string utf8String = [string UTF8String]; + // Input string may be NSString or NSAttributedString. + BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; + const NSString* rawString = isAttributedString ? [string string] : string; + std::string utf8String = rawString ? [rawString UTF8String] : ""; _activeModel->AddText(utf8String); if (_activeModel->composing()) { replacedRange = composingBeforeChange; diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm index 326960d82cbf3..fb47168e40431 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm @@ -2485,4 +2485,79 @@ - (bool)testInsertTextWithCollapsedSelectionInsideComposing { [[FlutterInputPluginTestObjc alloc] testInsertTextWithCollapsedSelectionInsideComposing]); } +TEST(FlutterTextInputPluginTest, InsertTextHandlesNSAttributedString) { + id engineMock = flutter::testing::CreateMockFlutterEngine(@""); + id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + OCMStub( // NOLINT(google-objc-avoid-throwing-exception) + [engineMock binaryMessenger]) + .andReturn(binaryMessengerMock); + + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock + nibName:@"" + bundle:nil]; + + FlutterTextInputPluginTestDelegate* delegate = + [[FlutterTextInputPluginTestDelegate alloc] initWithBinaryMessenger:binaryMessengerMock + viewController:viewController]; + + FlutterTextInputPlugin* plugin = [[FlutterTextInputPlugin alloc] initWithDelegate:delegate]; + + NSDictionary* setClientConfig = @{ + @"viewId" : @(kViewId), + @"inputAction" : @"action", + @"inputType" : @{@"name" : @"inputName"}, + }; + [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" + arguments:@[ @(1), setClientConfig ]] + result:^(id){ + }]; + + // Test with NSAttributedString + NSAttributedString* attributedString = + [[NSAttributedString alloc] initWithString:@"attributed text"]; + [plugin insertText:attributedString replacementRange:NSMakeRange(NSNotFound, 0)]; + + NSDictionary* editingState = [plugin editingState]; + EXPECT_STREQ([editingState[@"text"] UTF8String], "attributed text"); + EXPECT_EQ([editingState[@"selectionBase"] intValue], 15); + EXPECT_EQ([editingState[@"selectionExtent"] intValue], 15); +} + +TEST(FlutterTextInputPluginTest, InsertTextHandlesEmptyAttributedString) { + id engineMock = flutter::testing::CreateMockFlutterEngine(@""); + id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + OCMStub( // NOLINT(google-objc-avoid-throwing-exception) + [engineMock binaryMessenger]) + .andReturn(binaryMessengerMock); + + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock + nibName:@"" + bundle:nil]; + + FlutterTextInputPluginTestDelegate* delegate = + [[FlutterTextInputPluginTestDelegate alloc] initWithBinaryMessenger:binaryMessengerMock + viewController:viewController]; + + FlutterTextInputPlugin* plugin = [[FlutterTextInputPlugin alloc] initWithDelegate:delegate]; + + NSDictionary* setClientConfig = @{ + @"viewId" : @(kViewId), + @"inputAction" : @"action", + @"inputType" : @{@"name" : @"inputName"}, + }; + [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" + arguments:@[ @(1), setClientConfig ]] + result:^(id){ + }]; + + // Test with empty NSAttributedString + NSAttributedString* emptyAttributedString = [[NSAttributedString alloc] initWithString:@""]; + [plugin insertText:emptyAttributedString replacementRange:NSMakeRange(NSNotFound, 0)]; + + NSDictionary* editingState = [plugin editingState]; + EXPECT_STREQ([editingState[@"text"] UTF8String], ""); + EXPECT_EQ([editingState[@"selectionBase"] intValue], 0); + EXPECT_EQ([editingState[@"selectionExtent"] intValue], 0); +} + } // namespace flutter::testing diff --git a/engine/src/flutter/shell/platform/linux/BUILD.gn b/engine/src/flutter/shell/platform/linux/BUILD.gn index b4b161cbfa433..44ca902e4c8c5 100644 --- a/engine/src/flutter/shell/platform/linux/BUILD.gn +++ b/engine/src/flutter/shell/platform/linux/BUILD.gn @@ -153,6 +153,7 @@ source_set("flutter_linux_sources") { "fl_settings_channel.cc", "fl_settings_handler.cc", "fl_settings_portal.cc", + "fl_shorebird.cc", "fl_socket_accessible.cc", "fl_standard_message_codec.cc", "fl_standard_method_codec.cc", @@ -181,11 +182,13 @@ source_set("flutter_linux_sources") { deps = [ "//flutter/fml", + "//flutter/shell/common/shorebird", "//flutter/shell/platform/common:common_cpp_enums", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_switches", "//flutter/shell/platform/embedder:embedder_headers", "//flutter/third_party/rapidjson", + "//flutter/third_party/tonic", ] } diff --git a/engine/src/flutter/shell/platform/linux/fl_accessible_node.cc b/engine/src/flutter/shell/platform/linux/fl_accessible_node.cc index 7ce29f108fdf1..97b679834bdc3 100644 --- a/engine/src/flutter/shell/platform/linux/fl_accessible_node.cc +++ b/engine/src/flutter/shell/platform/linux/fl_accessible_node.cc @@ -83,6 +83,43 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, fl_accessible_node_action_interface_init)) +// Returns TRUE if [flags] indicate this element is checkable. +static gboolean is_checkable(FlutterSemanticsFlags flags) { + return flags.is_checked != kFlutterCheckStateNone || + flags.is_toggled != kFlutterTristateNone; +} + +// Returns TRUE if [flags] indicate this element is checked. +static gboolean is_checked(FlutterSemanticsFlags flags) { + return flags.is_checked == kFlutterCheckStateTrue || + flags.is_toggled == kFlutterTristateTrue; +} + +// Returns TRUE if [flags] indicate this element is focusable. +static gboolean is_focusable(FlutterSemanticsFlags flags) { + return flags.is_focused != kFlutterTristateNone; +} + +// Returns TRUE if [flags] indicate this element is focused. +static gboolean is_focused(FlutterSemanticsFlags flags) { + return flags.is_focused == kFlutterTristateTrue; +} + +// Returns TRUE if [flags] indicate this element is selected. +static gboolean is_selected(FlutterSemanticsFlags flags) { + return flags.is_selected == kFlutterTristateTrue; +} + +// Returns TRUE if [flags] indicate this element is sensitive. +static gboolean is_sensitive(FlutterSemanticsFlags flags) { + return flags.is_enabled != kFlutterTristateNone; +} + +// Returns TRUE if [flags] indicate this element is enabled. +static gboolean is_enabled(FlutterSemanticsFlags flags) { + return flags.is_enabled == kFlutterTristateTrue; +} + // Returns TRUE if [action] is set in [actions]. static gboolean has_action(FlutterSemanticsAction actions, FlutterSemanticsAction action) { @@ -237,23 +274,25 @@ static AtkStateSet* fl_accessible_node_ref_state_set(AtkObject* accessible) { if (!priv->flags.is_hidden) { atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); } - if (priv->flags.is_checked != kFlutterCheckStateNone) { + if (is_checkable(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_CHECKABLE); } - if (priv->flags.is_focused != kFlutterTristateNone) { + if (is_checked(priv->flags)) { + atk_state_set_add_state(state_set, ATK_STATE_CHECKED); + } + if (is_focusable(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); } - if (priv->flags.is_focused == kFlutterTristateTrue) { + if (is_focused(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); } - if (priv->flags.is_checked || priv->flags.is_toggled) { - atk_state_set_add_state(state_set, ATK_STATE_CHECKED); - } - if (priv->flags.is_selected) { + if (is_selected(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_SELECTED); } - if (priv->flags.is_enabled == kFlutterTristateTrue) { + if (is_enabled(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + } + if (is_sensitive(priv->flags)) { atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); } if (priv->flags.is_read_only) { @@ -372,43 +411,33 @@ static void fl_accessible_node_set_flags_impl(FlAccessibleNode* self, atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_VISIBLE, !flags->is_hidden); } - bool was_checkable = old_flags.is_checked != kFlutterCheckStateNone; - bool is_checkable = flags->is_checked != kFlutterCheckStateNone; - if (flag_changed(was_checkable, is_checkable)) { + if (flag_changed(is_checkable(old_flags), is_checkable(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_CHECKABLE, - is_checkable); + is_checkable(priv->flags)); } - if (flag_changed(old_flags.is_focused, flags->is_focused)) { + if (flag_changed(is_checked(old_flags), is_checked(priv->flags))) { + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_CHECKED, + is_checked(priv->flags)); + } + if (flag_changed(is_focusable(old_flags), is_focusable(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSABLE, - flags->is_focused != kFlutterTristateNone); + is_focusable(priv->flags)); } - if (flag_changed(old_flags.is_focused, flags->is_focused)) { + if (flag_changed(is_focused(old_flags), is_focused(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, - flags->is_focused == kFlutterTristateTrue); - } - bool old_is_checked = old_flags.is_checked || old_flags.is_toggled; - bool is_checked = flags->is_checked || flags->is_toggled; - if (flag_changed(old_is_checked, is_checked)) { - atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_CHECKED, - is_checked); + is_focused(priv->flags)); } - if (flag_changed(old_flags.is_selected, flags->is_selected)) { + if (flag_changed(is_selected(old_flags), is_selected(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_SELECTED, - flags->is_selected); + is_selected(priv->flags)); } - if (flag_changed(old_flags.is_enabled, flags->is_enabled)) { - atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_ENABLED, - flags->is_enabled); + if (flag_changed(is_sensitive(old_flags), is_sensitive(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_SENSITIVE, - flags->is_enabled); - } - if (flag_changed(old_flags.is_enabled, flags->is_enabled)) { - atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_ENABLED, - flags->is_enabled); + is_sensitive(priv->flags)); } - if (flag_changed(old_flags.is_enabled, flags->is_enabled)) { + if (flag_changed(is_enabled(old_flags), is_enabled(priv->flags))) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_ENABLED, - flags->is_enabled); + is_enabled(priv->flags)); } if (flag_changed(old_flags.is_read_only, flags->is_read_only)) { atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_READ_ONLY, diff --git a/engine/src/flutter/shell/platform/linux/fl_accessible_node.h b/engine/src/flutter/shell/platform/linux/fl_accessible_node.h index 1cfd2996e05ca..9edde348f33fc 100644 --- a/engine/src/flutter/shell/platform/linux/fl_accessible_node.h +++ b/engine/src/flutter/shell/platform/linux/fl_accessible_node.h @@ -166,7 +166,7 @@ void fl_accessible_node_set_text_direction(FlAccessibleNode* node, FlutterTextDirection direction); /** - * fl_accessible_node_dispatch_action: + * fl_accessible_node_perform_action: * @node: an #FlAccessibleNode. * @action: the action being dispatched. * @data: (allow-none): data associated with the action. diff --git a/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc b/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc index 85e61b66e38fe..577c49d5e6915 100644 --- a/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc @@ -6,12 +6,23 @@ #include "gtest/gtest.h" #include "flutter/shell/platform/linux/fl_accessible_node.h" +#include "flutter/shell/platform/linux/testing/mock_gtk.h" -// Checks can build a tree of nodes. -TEST(FlAccessibleNodeTest, BuildTree) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); +class FlAccessibleNodeTest : public ::testing::Test { + protected: + void SetUp() override { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + engine = fl_engine_new(project); + } + + ~FlAccessibleNodeTest() { g_object_unref(engine); } + + ::testing::NiceMock mock_gtk; + FlEngine* engine; +}; +// Checks can build a tree of nodes. +TEST_F(FlAccessibleNodeTest, BuildTree) { int64_t view_id = 123; g_autoptr(FlAccessibleNode) root = fl_accessible_node_new(engine, view_id, 0); g_autoptr(FlAccessibleNode) child1 = @@ -46,20 +57,14 @@ TEST(FlAccessibleNodeTest, BuildTree) { } // Checks node name is exposed to ATK. -TEST(FlAccessibleNodeTest, SetName) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); - +TEST_F(FlAccessibleNodeTest, SetName) { g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); fl_accessible_node_set_name(node, "test"); EXPECT_STREQ(atk_object_get_name(ATK_OBJECT(node)), "test"); } // Checks node extents are exposed to ATK. -TEST(FlAccessibleNodeTest, SetExtents) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); - +TEST_F(FlAccessibleNodeTest, SetExtents) { g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); fl_accessible_node_set_extents(node, 1, 2, 3, 4); gint x, y, width, height; @@ -71,31 +76,240 @@ TEST(FlAccessibleNodeTest, SetExtents) { EXPECT_EQ(height, 4); } -// Checks Flutter flags are mapped to appropriate ATK state. -TEST(FlAccessibleNodeTest, SetFlags) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); +// Checks the Flutter focused flag are mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, FocusedFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_focused = kFlutterTristateNone; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_FOCUSABLE)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_FOCUSED)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_focused = kFlutterTristateFalse; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_FOCUSABLE, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_FOCUSABLE)); + EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_FOCUSED)); + g_object_unref(state2); + + FlutterSemanticsFlags flags3 = {}; + flags3.is_focused = kFlutterTristateTrue; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_FOCUSED, TRUE)); + fl_accessible_node_set_flags(node, &flags3); + AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_FOCUSABLE)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_FOCUSED)); + g_object_unref(state3); +} +// Checks the Flutter checked and toggled flags are mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, CheckedAndToggledFlags) { g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); - FlutterSemanticsFlags flags = {}; - flags.is_enabled = kFlutterTristateTrue; - flags.is_focused = kFlutterTristateTrue; - fl_accessible_node_set_flags(node, &flags); - - AtkStateSet* state = atk_object_ref_state_set(ATK_OBJECT(node)); - EXPECT_TRUE(atk_state_set_contains_state(state, ATK_STATE_ENABLED)); - EXPECT_TRUE(atk_state_set_contains_state(state, ATK_STATE_SENSITIVE)); - EXPECT_TRUE(atk_state_set_contains_state(state, ATK_STATE_FOCUSABLE)); - EXPECT_TRUE(atk_state_set_contains_state(state, ATK_STATE_FOCUSED)); - EXPECT_TRUE(!atk_state_set_contains_state(state, ATK_STATE_CHECKED)); - g_object_unref(state); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_checked = kFlutterCheckStateNone; + flags1.is_toggled = kFlutterTristateNone; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_CHECKABLE)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_CHECKED)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_checked = kFlutterCheckStateFalse; + flags2.is_toggled = kFlutterTristateFalse; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_CHECKABLE, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_CHECKABLE)); + EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_CHECKED)); + g_object_unref(state2); + + FlutterSemanticsFlags flags3 = {}; + flags3.is_checked = kFlutterCheckStateTrue; + flags3.is_toggled = kFlutterTristateTrue; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_CHECKED, TRUE)); + fl_accessible_node_set_flags(node, &flags3); + AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_CHECKABLE)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_CHECKED)); + g_object_unref(state3); + + FlutterSemanticsFlags flags4 = {}; + flags4.is_checked = kFlutterCheckStateTrue; + flags4.is_toggled = kFlutterTristateNone; + fl_accessible_node_set_flags(node, &flags4); + AtkStateSet* state4 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state4, ATK_STATE_CHECKABLE)); + EXPECT_TRUE(atk_state_set_contains_state(state4, ATK_STATE_CHECKED)); + g_object_unref(state4); + + FlutterSemanticsFlags flags5 = {}; + flags5.is_checked = kFlutterCheckStateNone; + flags5.is_toggled = kFlutterTristateTrue; + fl_accessible_node_set_flags(node, &flags5); + AtkStateSet* state5 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state5, ATK_STATE_CHECKABLE)); + EXPECT_TRUE(atk_state_set_contains_state(state5, ATK_STATE_CHECKED)); + g_object_unref(state5); } -// Checks Flutter flags are mapped to appropriate ATK roles. -TEST(FlAccessibleNodeTest, GetRole) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); +// Checks the Flutter selected flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, SelectedFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_selected = kFlutterTristateNone; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SELECTED)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_selected = kFlutterTristateFalse; + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_SELECTED)); + g_object_unref(state2); + + FlutterSemanticsFlags flags3 = {}; + flags3.is_selected = kFlutterTristateTrue; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_SELECTED, TRUE)); + fl_accessible_node_set_flags(node, &flags3); + AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_SELECTED)); + g_object_unref(state3); +} +// Checks the Flutter enabled flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, EnabledFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_enabled = kFlutterTristateNone; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SENSITIVE)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_ENABLED)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_enabled = kFlutterTristateFalse; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_SENSITIVE, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_SENSITIVE)); + EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_ENABLED)); + g_object_unref(state2); + + FlutterSemanticsFlags flags3 = {}; + flags3.is_enabled = kFlutterTristateTrue; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_ENABLED, TRUE)); + fl_accessible_node_set_flags(node, &flags3); + AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_SENSITIVE)); + EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_ENABLED)); + g_object_unref(state3); +} + +// Checks the Flutter obscured flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, ObscuredFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_obscured = true; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SHOWING)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_obscured = false; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_SHOWING, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_SHOWING)); + g_object_unref(state2); +} + +// Checks the Flutter hidden flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, HiddenFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_hidden = true; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_VISIBLE)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_hidden = false; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_VISIBLE, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_VISIBLE)); + g_object_unref(state2); +} + +// Checks the Flutter read only flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, ReadOnlyFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_read_only = false; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_READ_ONLY)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_read_only = true; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_READ_ONLY, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_READ_ONLY)); + g_object_unref(state2); +} + +// Checks the Flutter text field flag is mapped to ATK flags. +TEST_F(FlAccessibleNodeTest, TextFieldFlags) { + g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); + + FlutterSemanticsFlags flags1 = {}; + flags1.is_text_field = false; + fl_accessible_node_set_flags(node, &flags1); + AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_EDITABLE)); + g_object_unref(state1); + + FlutterSemanticsFlags flags2 = {}; + flags2.is_text_field = true; + EXPECT_CALL(mock_gtk, atk_object_notify_state_change( + ::testing::_, ATK_STATE_EDITABLE, TRUE)); + fl_accessible_node_set_flags(node, &flags2); + AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node)); + EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_EDITABLE)); + g_object_unref(state2); +} + +// Checks Flutter flags are mapped to appropriate ATK roles. +TEST_F(FlAccessibleNodeTest, GetRole) { g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); FlutterSemanticsFlags flags1 = {}; @@ -132,10 +346,7 @@ TEST(FlAccessibleNodeTest, GetRole) { } // Checks Flutter actions are mapped to the appropriate ATK actions. -TEST(FlAccessibleNodeTest, SetActions) { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project); - +TEST_F(FlAccessibleNodeTest, SetActions) { g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0); fl_accessible_node_set_actions( node, static_cast( diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc index c30ad496e6286..5ec5697d7855b 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc @@ -228,8 +228,22 @@ static gboolean fl_compositor_opengl_present_layers(FlCompositor* compositor, glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao_binding); GLint saved_array_buffer_binding; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding); - GLint saved_framebuffer_binding; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &saved_framebuffer_binding); + GLint saved_draw_framebuffer_binding; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &saved_draw_framebuffer_binding); + GLint saved_read_framebuffer_binding; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &saved_read_framebuffer_binding); + GLint saved_current_program; + glGetIntegerv(GL_CURRENT_PROGRAM, &saved_current_program); + GLboolean saved_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + GLboolean saved_blend = glIsEnabled(GL_BLEND); + GLint saved_src_rgb; + glGetIntegerv(GL_BLEND_SRC_RGB, &saved_src_rgb); + GLint saved_src_alpha; + glGetIntegerv(GL_BLEND_SRC_ALPHA, &saved_src_alpha); + GLint saved_dst_rgb; + glGetIntegerv(GL_BLEND_DST_RGB, &saved_dst_rgb); + GLint saved_dst_alpha; + glGetIntegerv(GL_BLEND_DST_ALPHA, &saved_dst_alpha); // Update framebuffer to write into. size_t width = layers[0]->size.width; @@ -313,12 +327,24 @@ static gboolean fl_compositor_opengl_present_layers(FlCompositor* compositor, glDeleteVertexArrays(1, &vao); - glDisable(GL_BLEND); + if (saved_blend) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } + if (saved_scissor_test) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } glBindTexture(GL_TEXTURE_2D, saved_texture_binding); glBindVertexArray(saved_vao_binding); glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_framebuffer_binding); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_draw_framebuffer_binding); + glUseProgram(saved_current_program); + glBlendFuncSeparate(saved_src_rgb, saved_dst_rgb, saved_src_alpha, + saved_dst_alpha); if (!self->shareable) { glBindFramebuffer(GL_READ_FRAMEBUFFER, @@ -326,6 +352,7 @@ static gboolean fl_compositor_opengl_present_layers(FlCompositor* compositor, glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, self->pixels); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } + glBindFramebuffer(GL_READ_FRAMEBUFFER, saved_read_framebuffer_binding); g_mutex_unlock(&self->frame_mutex); diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc index 1faa5e4ce3071..003a13429306d 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc @@ -156,6 +156,8 @@ TEST(FlCompositorOpenGLTest, RestoresGLState) { constexpr GLuint kFakeTextureName = 123; glBindTexture(GL_TEXTURE_2D, kFakeTextureName); + glDisable(GL_BLEND); + glEnable(GL_SCISSOR_TEST); // Present layer and render. std::thread([&]() { @@ -175,6 +177,8 @@ TEST(FlCompositorOpenGLTest, RestoresGLState) { glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast(&texture_2d_binding)); EXPECT_EQ(texture_2d_binding, kFakeTextureName); + EXPECT_EQ(glIsEnabled(GL_BLEND), GL_FALSE); + EXPECT_EQ(glIsEnabled(GL_SCISSOR_TEST), GL_TRUE); } TEST(FlCompositorOpenGLTest, BlitFramebuffer) { diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 13b362c01ec47..1b446940256db 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc @@ -10,6 +10,7 @@ #include #include "flutter/common/constants.h" +#include "flutter/fml/logging.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" @@ -23,6 +24,7 @@ #include "flutter/shell/platform/linux/fl_platform_handler.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_settings_handler.h" +#include "flutter/shell/platform/linux/fl_shorebird.h" #include "flutter/shell/platform/linux/fl_texture_gl_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/fl_windowing_handler.h" @@ -777,6 +779,9 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { g_autoptr(GPtrArray) command_line_args = g_ptr_array_new_with_free_func(g_free); + // FlutterProjectArgs expects a full argv, so when processing it for flags + // the first item is treated as the executable and ignored. Add a dummy + // value so that all switches are used. g_ptr_array_insert(command_line_args, 0, g_strdup("flutter")); for (const auto& env_switch : flutter::GetSwitchesFromEnvironment()) { g_ptr_array_add(command_line_args, g_strdup(env_switch.c_str())); @@ -814,9 +819,22 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.compositor = &compositor; if (self->embedder_api.RunsAOTCompiledDartCode()) { + // This struct contains raw C strings and needs to have its lifetime scoped + // to this block. FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; - source.elf_path = fl_dart_project_get_aot_library_path(self->project); + std::string patch_path; + auto setup_shorebird_result = + flutter::SetUpShorebird(args.assets_path, patch_path); + if (setup_shorebird_result) { + // If we have a patch installed, we replace the default AOT library path + // with the patch path here. + source.elf_path = patch_path.c_str(); + } else { + FML_LOG(ERROR) << "Failed to configure Shorebird."; + source.elf_path = fl_dart_project_get_aot_library_path(self->project); + } + if (self->embedder_api.CreateAOTData(&source, &self->aot_data) != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, diff --git a/engine/src/flutter/shell/platform/linux/fl_shorebird.cc b/engine/src/flutter/shell/platform/linux/fl_shorebird.cc new file mode 100644 index 0000000000000..eb913ad720c61 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_shorebird.cc @@ -0,0 +1,56 @@ +#include "flutter/shell/platform/linux/fl_shorebird.h" + +#include +#include +#include + +#include "flutter/fml/file.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/paths.h" +#include "flutter/shell/common/shorebird/shorebird.h" +#include "rapidjson/document.h" +#include "third_party/tonic/filesystem/filesystem/file.h" + +// Namespaced to avoid Google style warnings. +namespace flutter { + +gboolean SetUpShorebird(const char* assets_path, std::string& patch_path) { + auto shorebird_yaml_path = + fml::paths::JoinPaths({assets_path, "shorebird.yaml"}); + std::string shorebird_yaml_contents(""); + if (!filesystem::ReadFileToString(shorebird_yaml_path, + &shorebird_yaml_contents)) { + FML_LOG(ERROR) << "Failed to read shorebird.yaml."; + return false; + } + + std::string code_cache_path = + fml::paths::JoinPaths({g_get_home_dir(), ".shorebird_cache"}); + auto executable_location = fml::paths::GetExecutableDirectoryPath().second; + auto app_path = + fml::paths::JoinPaths({executable_location, "lib", "libapp.so"}); + auto version_json_path = fml::paths::JoinPaths({assets_path, "version.json"}); + std::ifstream input(version_json_path); + if (!input) { + return false; + } + std::string json_contents{std::istreambuf_iterator(input), + std::istreambuf_iterator()}; + + rapidjson::Document json_doc; + json_doc.Parse(json_contents.c_str()); + if (json_doc.HasParseError()) { + // Could not parse version file, aborting. + return false; + } + + const auto version_map = json_doc.GetObject(); + ReleaseVersion release_version{version_map["version"].GetString(), + version_map["build_number"].GetString()}; + + ShorebirdConfigArgs shorebird_args(code_cache_path, code_cache_path, app_path, + shorebird_yaml_contents, release_version); + return ConfigureShorebird(shorebird_args, patch_path); +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/linux/fl_shorebird.h b/engine/src/flutter/shell/platform/linux/fl_shorebird.h new file mode 100644 index 0000000000000..e38965776ac97 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_shorebird.h @@ -0,0 +1,13 @@ +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_SHOREBIRD_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_SHOREBIRD_H_ + +#include +#include + +namespace flutter { + +gboolean SetUpShorebird(const char* assets_path, std::string& patch_path); + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_SHOREBIRD_H_ diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_epoxy.cc b/engine/src/flutter/shell/platform/linux/testing/mock_epoxy.cc index ee19426151d68..3194511c8a8ea 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_epoxy.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_epoxy.cc @@ -388,6 +388,17 @@ static GLuint bound_texture_2d; static std::map framebuffer_renderbuffers; +static GLboolean enable_blend = GL_FALSE; +static GLboolean enable_scissor_test = GL_FALSE; + +static void _setEnable(GLenum cap, GLboolean value) { + if (cap == GL_BLEND) { + enable_blend = value; + } else if (cap == GL_SCISSOR_TEST) { + enable_scissor_test = value; + } +} + void _glAttachShader(GLuint program, GLuint shader) {} static void _glBindFramebuffer(GLenum target, GLuint framebuffer) {} @@ -448,6 +459,14 @@ void _glDeleteTextures(GLsizei n, const GLuint* textures) { } } +static void _glDisable(GLenum cap) { + _setEnable(cap, GL_FALSE); +} + +static void _glEnable(GLenum cap) { + _setEnable(cap, GL_TRUE); +} + static void _glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, @@ -534,6 +553,16 @@ static const GLubyte* _glGetString(GLenum pname) { return mock->glGetString(pname); } +static GLboolean _glIsEnabled(GLenum cap) { + if (cap == GL_BLEND) { + return enable_blend; + } else if (cap == GL_SCISSOR_TEST) { + return enable_scissor_test; + } else { + return GL_FALSE; + } +} + static void _glTexParameterf(GLenum target, GLenum pname, GLfloat param) {} static void _glTexParameteri(GLenum target, GLenum pname, GLint param) {} @@ -724,6 +753,8 @@ static void library_init() { epoxy_glDeleteRenderbuffers = _glDeleteRenderbuffers; epoxy_glDeleteShader = _glDeleteShader; epoxy_glDeleteTextures = _glDeleteTextures; + epoxy_glDisable = _glDisable; + epoxy_glEnable = _glEnable; epoxy_glFramebufferRenderbuffer = _glFramebufferRenderbuffer; epoxy_glFramebufferTexture2D = _glFramebufferTexture2D; epoxy_glGenFramebuffers = _glGenFramebuffers; @@ -737,6 +768,7 @@ static void library_init() { epoxy_glGetShaderiv = _glGetShaderiv; epoxy_glGetShaderInfoLog = _glGetShaderInfoLog; epoxy_glGetString = _glGetString; + epoxy_glIsEnabled = _glIsEnabled; epoxy_glLinkProgram = _glLinkProgram; epoxy_glRenderbufferStorage = _glRenderbufferStorage; epoxy_glShaderSource = _glShaderSource; diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc index 85c59505e2617..17f22a1f52b52 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc @@ -376,3 +376,12 @@ void gtk_clipboard_request_text(GtkClipboard* clipboard, gpointer user_data) { check_thread(); } + +void atk_object_notify_state_change(AtkObject* accessible, + AtkState state, + gboolean value) { + check_thread(); + if (mock != nullptr) { + mock->atk_object_notify_state_change(accessible, state, value); + } +} diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.h b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.h index 71c5ffb9fea7b..6283365d49033 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.h +++ b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.h @@ -7,6 +7,7 @@ #include "gmock/gmock.h" +#include #include namespace flutter { @@ -74,6 +75,9 @@ class MockGtk { void, gtk_im_context_set_surrounding, (GtkIMContext * context, const gchar* text, gint len, gint cursor_index)); + MOCK_METHOD(void, + atk_object_notify_state_change, + (AtkObject * accessible, AtkState state, gboolean value)); GThread* thread; }; diff --git a/engine/src/flutter/shell/platform/windows/BUILD.gn b/engine/src/flutter/shell/platform/windows/BUILD.gn index 62730cc2f85df..993c4860a5f01 100644 --- a/engine/src/flutter/shell/platform/windows/BUILD.gn +++ b/engine/src/flutter/shell/platform/windows/BUILD.gn @@ -165,6 +165,7 @@ source_set("flutter_windows_source") { ":flutter_windows_headers", "//flutter/fml", "//flutter/impeller/renderer/backend/gles", + "//flutter/shell/common/shorebird", "//flutter/shell/geometry", "//flutter/shell/platform/common:common_cpp", "//flutter/shell/platform/common:common_cpp_input", @@ -180,6 +181,7 @@ source_set("flutter_windows_source") { "//flutter/third_party/angle:libEGL_static", "//flutter/third_party/angle:libGLESv2_static", "//flutter/third_party/rapidjson", + "//flutter/third_party/tonic", ] } @@ -191,6 +193,11 @@ copy("publish_headers_windows") { deps = [ "//flutter/shell/platform/common:publish_headers" ] } +copy("updater_exports_windows") { + sources = [ "flutter_windows.dll.def" ] + outputs = [ "$root_out_dir/{{source_file_part}}" ] +} + shared_library("flutter_windows") { deps = [ ":flutter_windows_source" ] @@ -305,6 +312,7 @@ group("windows") { deps = [ ":flutter_windows", ":publish_headers_windows", + ":updater_exports_windows", "//flutter/shell/platform/windows/client_wrapper:publish_wrapper_windows", ] diff --git a/engine/src/flutter/shell/platform/windows/flutter_project_bundle.cc b/engine/src/flutter/shell/platform/windows/flutter_project_bundle.cc index b63dad588a551..f2fc0be8756d0 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_project_bundle.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_project_bundle.cc @@ -7,6 +7,7 @@ #include #include "flutter/fml/logging.h" +#include "flutter/fml/string_conversion.h" #include "flutter/shell/platform/common/engine_switches.h" // nogncheck #include "flutter/shell/platform/common/path_utils.h" @@ -73,7 +74,7 @@ UniqueAotDataPtr FlutterProjectBundle::LoadAotData( << "; no such file."; return UniqueAotDataPtr(nullptr, nullptr); } - std::string path_string = aot_library_path_.string(); + std::string path_string = fml::PathToUtf8(aot_library_path_); FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; source.elf_path = path_string.c_str(); diff --git a/engine/src/flutter/shell/platform/windows/flutter_project_bundle.h b/engine/src/flutter/shell/platform/windows/flutter_project_bundle.h index 8fa12bc8b953a..7396dc2349e5c 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_project_bundle.h +++ b/engine/src/flutter/shell/platform/windows/flutter_project_bundle.h @@ -55,6 +55,10 @@ class FlutterProjectBundle { // Sets engine switches. void SetSwitches(const std::vector& switches); + void SetAotLibraryPath(const std::filesystem::path& aot_library_path) { + aot_library_path_ = aot_library_path; + } + // Attempts to load AOT data for this bundle. The returned data must be // retained until any engine instance it is passed to has been shut down. // diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows.dll.def b/engine/src/flutter/shell/platform/windows/flutter_windows.dll.def new file mode 100644 index 0000000000000..bcaa785977259 --- /dev/null +++ b/engine/src/flutter/shell/platform/windows/flutter_windows.dll.def @@ -0,0 +1,17 @@ +EXPORTS + shorebird_check_for_downloadable_update = shorebird_check_for_downloadable_update + shorebird_check_for_update = shorebird_check_for_update + shorebird_current_boot_patch_number = shorebird_current_boot_patch_number + shorebird_free_string = shorebird_free_string + shorebird_free_update_result = shorebird_free_update_result + shorebird_init = shorebird_init + shorebird_next_boot_patch_number = shorebird_next_boot_patch_number + shorebird_next_boot_patch_path = shorebird_next_boot_patch_path + shorebird_validate_next_boot_patch = shorebird_validate_next_boot_patch + shorebird_report_launch_failure = shorebird_report_launch_failure + shorebird_report_launch_start = shorebird_report_launch_start + shorebird_report_launch_success = shorebird_report_launch_success + shorebird_should_auto_update = shorebird_should_auto_update + shorebird_start_update_thread = shorebird_start_update_thread + shorebird_update = shorebird_update + shorebird_update_with_result = shorebird_update_with_result \ No newline at end of file diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc index d579c818ecfa3..22b028beb03f4 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -5,15 +5,20 @@ #include "flutter/shell/platform/windows/flutter_windows_engine.h" #include +#include +#include +#include #include #include #include +#include #include "flutter/fml/logging.h" #include "flutter/fml/paths.h" #include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/shell/common/shorebird/shorebird.h" #include "flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h" #include "flutter/shell/platform/common/path_utils.h" @@ -29,6 +34,7 @@ #include "flutter/shell/platform/windows/window_manager.h" #include "flutter/third_party/accessibility/ax/ax_node.h" #include "shell/platform/windows/flutter_project_bundle.h" +#include "third_party/tonic/filesystem/filesystem/file.h" // winbase.h defines GetCurrentTime as a macro. #undef GetCurrentTime @@ -269,13 +275,145 @@ bool FlutterWindowsEngine::Run() { return Run(""); } +int GetReleaseVersionAndBuildNumber(ReleaseVersion* release_version) { + char module_path[MAX_PATH]; + // Get the full path of the currently running executable. The return value is + // the size of the string that was copied to the buffer, with -1 indicating + // failure. + if (GetModuleFileNameA(NULL, module_path, MAX_PATH) == -1) { + return -1; + } + + // Get the size of the version information + DWORD handle = -1; + DWORD version_info_size = GetFileVersionInfoSizeA(module_path, &handle); + if (version_info_size == -1) { + return -1; + } + + // Allocate memory for version info + std::unique_ptr version_data(new char[version_info_size]); + if (!GetFileVersionInfoA(module_path, handle, version_info_size, + version_data.get())) { + return -1; + } + + // Adopted from + // https://learn.microsoft.com/en-us/windows/win32/api/winver/nf-winver-verqueryvaluea + // Get the translation table + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + }* lpTranslate; + + UINT cbTranslate = 0; + if (!VerQueryValueA(version_data.get(), "\\VarFileInfo\\Translation", + (LPVOID*)&lpTranslate, &cbTranslate)) { + FML_LOG(ERROR) << "Error: Unable to get translation info."; + return -1; + } + + // Construct the query string using the first translation found + char subBlock[64]; + sprintf_s(subBlock, "\\StringFileInfo\\%04x%04x\\ProductVersion", + lpTranslate[0].wLanguage, lpTranslate[0].wCodePage); + + LPSTR versionString = nullptr; + UINT size = 0; + if (!VerQueryValueA(version_data.get(), subBlock, (LPVOID*)&versionString, + &size)) { + return -1; + } + + if (!versionString) { + return -1; + } + + // The version string is in the format of "1.0.0+1", with the label ("+1") + // being optional. + auto version = std::string(versionString); + auto plusPos = version.find("+"); + if (plusPos != std::string::npos) { + auto semVer = version.substr(0, plusPos); + auto patch = version.substr(plusPos + 1, version.length()); + release_version->version = semVer; + release_version->build_number = patch; + } else { + release_version->version = version; + } + + return kSuccess; +} + +bool GetLocalAppDataPath(std::string& outPath) { + PWSTR path = nullptr; + HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path); + if (!SUCCEEDED(result)) { + return false; + } + + std::wstring widePath(path); + std::string localAppDataPath(widePath.begin(), widePath.end()); + // The calling process is responsible for freeing this resource + // https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath + CoTaskMemFree(path); + outPath = localAppDataPath; + return true; +} + +bool SetUpShorebird(std::string assets_path_string, std::string& patch_path) { + auto shorebird_yaml_path = + fml::paths::JoinPaths({assets_path_string, "shorebird.yaml"}); + std::string shorebird_yaml_contents(""); + if (!filesystem::ReadFileToString(shorebird_yaml_path, + &shorebird_yaml_contents)) { + FML_LOG(ERROR) << "Failed to read shorebird.yaml."; + return false; + } + + std::string code_cache_path; + if (!GetLocalAppDataPath(code_cache_path)) { + FML_LOG(ERROR) << "Failed to retrieve the local AppData directory."; + return false; + } + + auto executable_location = fml::paths::GetExecutableDirectoryPath().second; + auto app_path = + fml::paths::JoinPaths({executable_location, "data", "app.so"}); + ReleaseVersion release_version; + auto release_version_result = + GetReleaseVersionAndBuildNumber(&release_version); + if (release_version_result != kSuccess) { + FML_LOG(ERROR) + << "Failed to retrieve the release version and build number."; + return false; + } + + ShorebirdConfigArgs shorebird_args(code_cache_path, code_cache_path, app_path, + shorebird_yaml_contents, release_version); + return ConfigureShorebird(shorebird_args, patch_path); +} + bool FlutterWindowsEngine::Run(std::string_view entrypoint) { if (!project_->HasValidPaths()) { FML_LOG(ERROR) << "Missing or unresolvable paths to assets."; return false; } - std::string assets_path_string = project_->assets_path().string(); - std::string icu_path_string = project_->icu_path().string(); + std::string assets_path_string = fml::PathToUtf8(project_->assets_path()); + std::string icu_path_string = fml::PathToUtf8(project_->icu_path()); + + std::string patch_path; + auto setup_shorebird_result = SetUpShorebird(assets_path_string, patch_path); + if (setup_shorebird_result) { + // If we have a patch installed, we replace the default AOT library path + // with the patch path here. + FML_LOG(INFO) << "Setting project patch path: " << patch_path; + project_->SetAotLibraryPath(patch_path); + } else { + FML_LOG(ERROR) << "Failed to configure Shorebird."; + } + + // This loads AOT data from the project_'s aot_library_path_. if (embedder_api_.RunsAOTCompiledDartCode()) { aot_data_ = project_->LoadAotData(embedder_api_); if (!aot_data_) { @@ -406,6 +544,15 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { host->root_isolate_create_callback_(); } }; + // Copied from shell\platform\darwin\macos\framework\Source\FlutterEngine.mm + // Writes log messages to stdout. + args.log_message_callback = [](const char* tag, const char* message, + void* user_data) { + if (tag && tag[0]) { + std::cout << tag << ": "; + } + std::cout << message << std::endl; + }; args.channel_update_callback = [](const FlutterChannelUpdate* update, void* user_data) { auto host = static_cast(user_data); diff --git a/engine/src/flutter/shell/testing/BUILD.gn b/engine/src/flutter/shell/testing/BUILD.gn index 28a19c75d1bb9..ce47535e8db12 100644 --- a/engine/src/flutter/shell/testing/BUILD.gn +++ b/engine/src/flutter/shell/testing/BUILD.gn @@ -38,6 +38,7 @@ executable("testing") { deps = [ "$dart_src/runtime:libdart_jit", "$dart_src/runtime/bin:dart_io_api", + "$dart_src/runtime/bin:elf_loader", "//flutter/assets", "//flutter/common", "//flutter/flow", diff --git a/engine/src/flutter/sky/tools/create_ios_framework.py b/engine/src/flutter/sky/tools/create_ios_framework.py index d87e0f91bff49..0ead267e9609e 100644 --- a/engine/src/flutter/sky/tools/create_ios_framework.py +++ b/engine/src/flutter/sky/tools/create_ios_framework.py @@ -19,7 +19,8 @@ def main(): parser = argparse.ArgumentParser( description=( 'Creates Flutter.framework, Flutter.xcframework and ' - 'copies architecture-dependent gen_snapshot binaries to output dir' + 'copies architecture-dependent analyze_snapshot and gen_snapshot ' + 'binaries to output dir' ) ) @@ -89,13 +90,17 @@ def main(): '%s_extension_safe' % simulator_x64_out_dir, '%s_extension_safe' % simulator_arm64_out_dir ) - # Copy gen_snapshot binary to destination directory. + # Copy analyze_snapshot and gen_snapshot binaries to destination directory. if arm64_out_dir: gen_snapshot = os.path.join(arm64_out_dir, 'universal', 'gen_snapshot_arm64') + analyze_snapshot = os.path.join(arm64_out_dir, 'analyze_snapshot_arm64') sky_utils.copy_binary(gen_snapshot, os.path.join(dst, 'gen_snapshot_arm64')) + sky_utils.copy_binary(analyze_snapshot, os.path.join(dst, 'analyze_snapshot_arm64')) if x64_out_dir: gen_snapshot = os.path.join(x64_out_dir, 'universal', 'gen_snapshot_x64') + analyze_snapshot = os.path.join(x64_out_dir, 'analyze_snapshot_x64') sky_utils.copy_binary(gen_snapshot, os.path.join(dst, 'gen_snapshot_x64')) + sky_utils.copy_binary(analyze_snapshot, os.path.join(dst, 'analyze_snapshot_x64')) zip_archive(dst, args) return 0 @@ -177,7 +182,7 @@ def zip_archive(dst, args): # See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130 # Binaries that must be codesigned and require entitlements for particular APIs. - with_entitlements = ['gen_snapshot_arm64'] + with_entitlements = ['analyze_snapshot_arm64', 'gen_snapshot_arm64'] with_entitlements_file = os.path.join(dst, 'entitlements.txt') sky_utils.write_codesign_config(with_entitlements_file, with_entitlements) @@ -211,6 +216,7 @@ def zip_archive(dst, args): # pylint: enable=line-too-long zip_contents = [ + 'analyze_snapshot_arm64', 'gen_snapshot_arm64', 'Flutter.xcframework', 'entitlements.txt', diff --git a/engine/src/flutter/testing/run_tests.py b/engine/src/flutter/testing/run_tests.py index bfd5872374658..712d6ed50a26e 100755 --- a/engine/src/flutter/testing/run_tests.py +++ b/engine/src/flutter/testing/run_tests.py @@ -448,6 +448,7 @@ def make_test(name, flags=None, extra_env=None): make_test('platform_view_android_delegate_unittests'), # https://github.com/flutter/flutter/issues/36295 make_test('shell_unittests'), + make_test('shorebird_unittests'), ] if is_windows(): diff --git a/engine/src/flutter/tools/templater/templater_main.cc b/engine/src/flutter/tools/templater/templater_main.cc index c803d7290b9af..0bff26e581237 100644 --- a/engine/src/flutter/tools/templater/templater_main.cc +++ b/engine/src/flutter/tools/templater/templater_main.cc @@ -12,6 +12,7 @@ #include "flutter/fml/file.h" #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" +#include "flutter/fml/string_conversion.h" #include "inja/inja.hpp" namespace flutter { @@ -50,9 +51,9 @@ bool TemplaterMain(const fml::CommandLine& command_line) { reinterpret_cast(rendered_template.data()), rendered_template.size()}; - auto current_dir = - fml::OpenDirectory(std::filesystem::current_path().string().c_str(), - false, fml::FilePermission::kReadWrite); + auto current_dir = fml::OpenDirectory( + fml::PathToUtf8(std::filesystem::current_path()).c_str(), false, + fml::FilePermission::kReadWrite); if (!current_dir.is_valid()) { FML_LOG(ERROR) << "Could not open current directory."; return false; diff --git a/examples/hello_world/android/buildscript-gradle.lockfile b/examples/hello_world/android/buildscript-gradle.lockfile index 56cb3f708c29c..0b497c33be024 100644 --- a/examples/hello_world/android/buildscript-gradle.lockfile +++ b/examples/hello_world/android/buildscript-gradle.lockfile @@ -1,68 +1,67 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -androidx.databinding:databinding-common:8.7.0=classpath -androidx.databinding:databinding-compiler-common:8.7.0=classpath -com.android.application:com.android.application.gradle.plugin:8.7.0=classpath -com.android.databinding:baseLibrary:8.7.0=classpath -com.android.tools.analytics-library:crash:31.7.0=classpath -com.android.tools.analytics-library:protos:31.7.0=classpath -com.android.tools.analytics-library:shared:31.7.0=classpath -com.android.tools.analytics-library:tracker:31.7.0=classpath +androidx.databinding:databinding-common:8.11.1=classpath +androidx.databinding:databinding-compiler-common:8.11.1=classpath +com.android.application:com.android.application.gradle.plugin:8.11.1=classpath +com.android.databinding:baseLibrary:8.11.1=classpath +com.android.tools.analytics-library:crash:31.11.1=classpath +com.android.tools.analytics-library:protos:31.11.1=classpath +com.android.tools.analytics-library:shared:31.11.1=classpath +com.android.tools.analytics-library:tracker:31.11.1=classpath com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath -com.android.tools.build:aapt2-proto:8.7.0-12006047=classpath -com.android.tools.build:aaptcompiler:8.7.0=classpath -com.android.tools.build:apksig:8.7.0=classpath -com.android.tools.build:apkzlib:8.7.0=classpath -com.android.tools.build:builder-model:8.7.0=classpath -com.android.tools.build:builder-test-api:8.7.0=classpath -com.android.tools.build:builder:8.7.0=classpath -com.android.tools.build:bundletool:1.17.1=classpath -com.android.tools.build:gradle-api:8.7.0=classpath -com.android.tools.build:gradle-settings-api:8.7.0=classpath -com.android.tools.build:gradle:8.7.0=classpath -com.android.tools.build:manifest-merger:31.7.0=classpath +com.android.tools.build:aapt2-proto:8.11.1-12782657=classpath +com.android.tools.build:aaptcompiler:8.11.1=classpath +com.android.tools.build:apksig:8.11.1=classpath +com.android.tools.build:apkzlib:8.11.1=classpath +com.android.tools.build:builder-model:8.11.1=classpath +com.android.tools.build:builder-test-api:8.11.1=classpath +com.android.tools.build:builder:8.11.1=classpath +com.android.tools.build:bundletool:1.18.1=classpath +com.android.tools.build:gradle-api:8.11.1=classpath +com.android.tools.build:gradle-settings-api:8.11.1=classpath +com.android.tools.build:gradle:8.11.1=classpath +com.android.tools.build:manifest-merger:31.11.1=classpath com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath -com.android.tools.ddms:ddmlib:31.7.0=classpath -com.android.tools.layoutlib:layoutlib-api:31.7.0=classpath -com.android.tools.lint:lint-model:31.7.0=classpath -com.android.tools.lint:lint-typedef-remover:31.7.0=classpath -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=classpath -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=classpath -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=classpath -com.android.tools:annotations:31.7.0=classpath -com.android.tools:common:31.7.0=classpath -com.android.tools:dvlib:31.7.0=classpath -com.android.tools:repository:31.7.0=classpath -com.android.tools:sdk-common:31.7.0=classpath -com.android.tools:sdklib:31.7.0=classpath -com.android:signflinger:8.7.0=classpath -com.android:zipflinger:8.7.0=classpath +com.android.tools.ddms:ddmlib:31.11.1=classpath +com.android.tools.layoutlib:layoutlib-api:31.11.1=classpath +com.android.tools.lint:lint-model:31.11.1=classpath +com.android.tools.lint:lint-typedef-remover:31.11.1=classpath +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=classpath +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=classpath +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=classpath +com.android.tools:annotations:31.11.1=classpath +com.android.tools:common:31.11.1=classpath +com.android.tools:dvlib:31.11.1=classpath +com.android.tools:repository:31.11.1=classpath +com.android.tools:sdk-common:31.11.1=classpath +com.android.tools:sdklib:31.11.1=classpath +com.android:signflinger:8.11.1=classpath +com.android:zipflinger:8.11.1=classpath com.google.android:annotations:4.1.1.4=classpath -com.google.api.grpc:proto-google-common-protos:2.17.0=classpath +com.google.api.grpc:proto-google-common-protos:2.48.0=classpath com.google.auto.value:auto-value-annotations:1.6.2=classpath com.google.code.findbugs:jsr305:3.0.2=classpath -com.google.code.gson:gson:2.10.1=classpath +com.google.code.gson:gson:2.11.0=classpath com.google.crypto.tink:tink:1.7.0=classpath com.google.dagger:dagger:2.28.3=classpath -com.google.errorprone:error_prone_annotations:2.18.0=classpath +com.google.errorprone:error_prone_annotations:2.30.0=classpath com.google.flatbuffers:flatbuffers-java:1.12.0=classpath -com.google.guava:failureaccess:1.0.1=classpath -com.google.guava:guava:32.0.1-jre=classpath +com.google.guava:failureaccess:1.0.2=classpath +com.google.guava:guava:33.3.1-jre=classpath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath -com.google.j2objc:j2objc-annotations:2.8=classpath +com.google.j2objc:j2objc-annotations:3.0.0=classpath com.google.jimfs:jimfs:1.1=classpath -com.google.protobuf:protobuf-java-util:3.22.3=classpath -com.google.protobuf:protobuf-java:3.22.3=classpath -com.google.testing.platform:core-proto:0.0.9-alpha02=classpath +com.google.protobuf:protobuf-java-util:3.25.5=classpath +com.google.protobuf:protobuf-java:3.25.5=classpath +com.google.testing.platform:core-proto:0.0.9-alpha03=classpath com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath com.squareup:javapoet:1.10.0=classpath com.squareup:javawriter:2.5.0=classpath @@ -70,27 +69,29 @@ com.sun.activation:javax.activation:1.2.0=classpath com.sun.istack:istack-commons-runtime:3.0.8=classpath com.sun.xml.fastinfoset:FastInfoset:1.2.16=classpath commons-codec:commons-codec:1.11=classpath -commons-io:commons-io:2.13.0=classpath +commons-io:commons-io:2.16.1=classpath commons-logging:commons-logging:1.2=classpath -io.grpc:grpc-api:1.57.0=classpath -io.grpc:grpc-context:1.57.0=classpath -io.grpc:grpc-core:1.57.0=classpath -io.grpc:grpc-netty:1.57.0=classpath -io.grpc:grpc-protobuf-lite:1.57.0=classpath -io.grpc:grpc-protobuf:1.57.0=classpath -io.grpc:grpc-stub:1.57.0=classpath -io.netty:netty-buffer:4.1.93.Final=classpath -io.netty:netty-codec-http2:4.1.93.Final=classpath -io.netty:netty-codec-http:4.1.93.Final=classpath -io.netty:netty-codec-socks:4.1.93.Final=classpath -io.netty:netty-codec:4.1.93.Final=classpath -io.netty:netty-common:4.1.93.Final=classpath -io.netty:netty-handler-proxy:4.1.93.Final=classpath -io.netty:netty-handler:4.1.93.Final=classpath -io.netty:netty-resolver:4.1.93.Final=classpath -io.netty:netty-transport-native-unix-common:4.1.93.Final=classpath -io.netty:netty-transport:4.1.93.Final=classpath -io.perfmark:perfmark-api:0.26.0=classpath +io.grpc:grpc-api:1.69.1=classpath +io.grpc:grpc-context:1.69.1=classpath +io.grpc:grpc-core:1.69.1=classpath +io.grpc:grpc-inprocess:1.69.1=classpath +io.grpc:grpc-netty:1.69.1=classpath +io.grpc:grpc-protobuf-lite:1.69.1=classpath +io.grpc:grpc-protobuf:1.69.1=classpath +io.grpc:grpc-stub:1.69.1=classpath +io.grpc:grpc-util:1.69.1=classpath +io.netty:netty-buffer:4.1.110.Final=classpath +io.netty:netty-codec-http2:4.1.110.Final=classpath +io.netty:netty-codec-http:4.1.110.Final=classpath +io.netty:netty-codec-socks:4.1.110.Final=classpath +io.netty:netty-codec:4.1.110.Final=classpath +io.netty:netty-common:4.1.110.Final=classpath +io.netty:netty-handler-proxy:4.1.110.Final=classpath +io.netty:netty-handler:4.1.110.Final=classpath +io.netty:netty-resolver:4.1.110.Final=classpath +io.netty:netty-transport-native-unix-common:4.1.110.Final=classpath +io.netty:netty-transport:4.1.110.Final=classpath +io.perfmark:perfmark-api:0.27.0=classpath jakarta.activation:jakarta.activation-api:1.2.1=classpath jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath javax.annotation:javax.annotation-api:1.3.2=classpath @@ -104,50 +105,51 @@ org.apache.httpcomponents:httpclient:4.5.14=classpath org.apache.httpcomponents:httpcore:4.4.16=classpath org.apache.httpcomponents:httpmime:4.5.6=classpath org.bitbucket.b_c:jose4j:0.9.5=classpath -org.bouncycastle:bcpkix-jdk18on:1.77=classpath -org.bouncycastle:bcprov-jdk18on:1.77=classpath -org.bouncycastle:bcutil-jdk18on:1.77=classpath -org.checkerframework:checker-qual:3.33.0=classpath -org.codehaus.mojo:animal-sniffer-annotations:1.23=classpath +org.bouncycastle:bcpkix-jdk18on:1.79=classpath +org.bouncycastle:bcprov-jdk18on:1.79=classpath +org.bouncycastle:bcutil-jdk18on:1.79=classpath +org.checkerframework:checker-qual:3.43.0=classpath +org.codehaus.mojo:animal-sniffer-annotations:1.24=classpath org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath org.glassfish.jaxb:txw2:2.3.2=classpath org.jdom:jdom2:2.0.6=classpath -org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath -org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-statistics:2.1.0=classpath -org.jetbrains.kotlin:kotlin-build-tools-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-compiler-runner:2.1.0=classpath -org.jetbrains.kotlin:kotlin-daemon-client:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0=classpath -org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.1.0=classpath -org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.1.0=classpath -org.jetbrains.kotlin:kotlin-native-utils:2.1.0=classpath -org.jetbrains.kotlin:kotlin-reflect:1.9.24=classpath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=classpath -org.jetbrains.kotlin:kotlin-stdlib:1.9.24=classpath -org.jetbrains.kotlin:kotlin-tooling-core:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-io:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib-metadata:2.1.0=classpath -org.jetbrains.kotlin:kotlin-util-klib:2.1.0=classpath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath +org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.2.20=classpath +org.jetbrains.kotlin:abi-tools-api:2.2.20=classpath +org.jetbrains.kotlin:fus-statistics-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-statistics:2.2.20=classpath +org.jetbrains.kotlin:kotlin-build-tools-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-compiler-runner:2.2.20=classpath +org.jetbrains.kotlin:kotlin-daemon-client:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20=classpath +org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.2.20=classpath +org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.2.20=classpath +org.jetbrains.kotlin:kotlin-native-utils:2.2.20=classpath +org.jetbrains.kotlin:kotlin-reflect:2.0.21=classpath +org.jetbrains.kotlin:kotlin-stdlib-common:2.0.21=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=classpath +org.jetbrains.kotlin:kotlin-stdlib:2.0.21=classpath +org.jetbrains.kotlin:kotlin-tooling-core:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-io:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib-metadata:2.2.20=classpath +org.jetbrains.kotlin:kotlin-util-klib:2.2.20=classpath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.0=classpath org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0=classpath org.jetbrains:annotations:13.0=classpath org.jvnet.staxex:stax-ex:1.8.1=classpath -org.ow2.asm:asm-analysis:9.6=classpath -org.ow2.asm:asm-commons:9.6=classpath -org.ow2.asm:asm-tree:9.6=classpath -org.ow2.asm:asm-util:9.6=classpath -org.ow2.asm:asm:9.6=classpath +org.ow2.asm:asm-analysis:9.7.1=classpath +org.ow2.asm:asm-commons:9.7.1=classpath +org.ow2.asm:asm-tree:9.7.1=classpath +org.ow2.asm:asm-util:9.7.1=classpath +org.ow2.asm:asm:9.7.1=classpath org.slf4j:slf4j-api:1.7.30=classpath -org.tensorflow:tensorflow-lite-metadata:0.1.0-rc2=classpath +org.tensorflow:tensorflow-lite-metadata:0.2.0=classpath empty= diff --git a/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties b/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0a835..e4ef43fb98df4 100644 --- a/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties +++ b/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/examples/hello_world/android/project-app.lockfile b/examples/hello_world/android/project-app.lockfile index bfffc96e588c6..51732ade2947f 100644 --- a/examples/hello_world/android/project-app.lockfile +++ b/examples/hello_world/android/project-app.lockfile @@ -34,93 +34,166 @@ androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompile androidx.window.extensions.core:core:1.0.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.window:window-java:1.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.ddms:ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-ddmlib:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib -com.android.tools.utp:android-device-provider-gradle-proto:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-gradle:31.7.0=_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile-proto:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-device-provider-profile:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-additional-test-output:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output -com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-apk-installer:31.7.0=_internal-unified-test-platform-android-test-plugin-host-apk-installer -com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-coverage:31.7.0=_internal-unified-test-platform-android-test-plugin-host-coverage -com.android.tools.utp:android-test-plugin-host-device-info-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-device-info:31.7.0=_internal-unified-test-platform-android-test-plugin-host-device-info -com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-emulator-control:31.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat -com.android.tools.utp:android-test-plugin-host-logcat:31.7.0=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.ddms:ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.emulator:proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.11.1=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.11.1=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.11.1=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.11.1=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.11.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.11.1=_internal-unified-test-platform-android-test-plugin-host-logcat com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-test-plugin-host-retention:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:android-test-plugin-result-listener-gradle:31.7.0=_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention -com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.android.tools:common:31.7.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.11.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.11.1=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:utp-common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:annotations:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:common:31.11.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.7.0=_internal-unified-test-platform-android-test-plugin-host-retention com.getkeepsafe.relinker:relinker:1.4.5=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.api.grpc:proto-google-common-protos:2.48.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +com.google.code.gson:gson:2.11.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat +com.google.errorprone:error_prone_annotations:2.30.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:failureaccess:1.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.guava:listenablefuture:1.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control -com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin -com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core -com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher -commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention -io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core +com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.protobuf:protobuf-java:3.25.5=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-kotlin:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:android-device-provider-local:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha03=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-retention +com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-retention +commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-api:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-context:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-core:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-core:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-inprocess:1.69.1=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-netty:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-netty:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf-lite:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf-lite:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-protobuf:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-protobuf:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-services:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-retention +io.grpc:grpc-stub:1.57.2=_internal-unified-test-platform-core +io.grpc:grpc-stub:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-util:1.69.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http2:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-http:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec-socks:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-codec:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler-proxy:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-handler:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-resolver:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport-native-unix-common:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.netty:netty-transport:4.1.110.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.opencensus:opencensus-api:0.31.0=_internal-unified-test-platform-core +io.opencensus:opencensus-proto:0.2.0=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +io.perfmark:perfmark-api:0.27.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib -org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-core +org.codehaus.mojo:animal-sniffer-annotations:1.24=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-reflect:1.8.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.8.21=_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-core org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:1.9.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-launcher +org.jetbrains.kotlin:kotlin-stdlib:1.9.20=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:atomicfu:0.22.0=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-test-plugin-host-retention org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-test-plugin-host-retention +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath empty=androidApis,androidJdkImage,androidTestUtil,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestRuntimeClasspath,debugAnnotationProcessorClasspath,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,debugWearBundling,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileReverseMetadataValues,profileUnitTestAnnotationProcessorClasspath,profileWearBundling,releaseAnnotationProcessorClasspath,releaseReverseMetadataValues,releaseUnitTestAnnotationProcessorClasspath,releaseWearBundling diff --git a/examples/hello_world/android/settings.gradle.kts b/examples/hello_world/android/settings.gradle.kts index f55690b8599f8..f2b4712ff7438 100644 --- a/examples/hello_world/android/settings.gradle.kts +++ b/examples/hello_world/android/settings.gradle.kts @@ -34,8 +34,8 @@ buildscript { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/flutter_tools/doc/daemon.md b/packages/flutter_tools/doc/daemon.md index 1d4a4a381ab15..015688fadb4e7 100644 --- a/packages/flutter_tools/doc/daemon.md +++ b/packages/flutter_tools/doc/daemon.md @@ -183,6 +183,18 @@ This is sent once the application launch process is complete and the app is eith This is sent when output is logged for a running application. The `params` field will be a map with the fields `appId` and `log`. The `log` field is a string with the output text. If the output indicates an error, an `error` boolean field will be present, and set to `true`. +#### app.warning + +This is sent when a warning is issued for a running application that an editor may wish to handle specifically. The `params` field will be a map with the following fields: + +- `warningId`: A unique string identifying the warning type, suitable for client-side suppression. +- `warning`: A string containing the warning message to be displayed to the user. +- `category`: A string used to categorize the warning (for example, `ios-wireless-performance`). +- `deviceId`: The ID of the device this warning is relevant to. +- `deviceOsVersion`: An optional string representing the OS version of the device. +- `actionable`: A boolean indicating if the warning includes a suggested action for the user. +- `url`: An optional string containing a URL with more information about the warning. + #### app.progress This is sent when an operation starts and again when it stops. When an operation starts, the event contains the fields `id`, an opaque identifier, and `message` containing text describing the operation. When that same operation ends, the event contains the same `id` field value as when the operation started, along with a `finished` bool field with the value true, but no `message` field. diff --git a/packages/flutter_tools/gradle/aar_init_script.gradle b/packages/flutter_tools/gradle/aar_init_script.gradle index 0d43a9b103fd2..0abc801a2fb62 100644 --- a/packages/flutter_tools/gradle/aar_init_script.gradle +++ b/packages/flutter_tools/gradle/aar_init_script.gradle @@ -42,7 +42,7 @@ void configureProject(Project project, String outputDir) { return } - String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://storage.googleapis.com" + String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://download.shorebird.dev" String engineRealm = Paths.get(getFlutterRoot(project), "bin", "cache", "engine.realm") .toFile().text.trim() diff --git a/packages/flutter_tools/gradle/build.gradle.kts b/packages/flutter_tools/gradle/build.gradle.kts index e0265f532530c..84a0f8a6e2ca8 100644 --- a/packages/flutter_tools/gradle/build.gradle.kts +++ b/packages/flutter_tools/gradle/build.gradle.kts @@ -62,10 +62,11 @@ dependencies { // * AGP version constants in packages/flutter_tools/lib/src/android/gradle_utils.dart // * ndkVersion constant in packages/flutter_tools/lib/src/android/gradle_utils.dart // * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt - compileOnly("com.android.tools.build:gradle:8.9.1") + compileOnly("com.android.tools.build:gradle:8.11.1") + implementation("org.yaml:snakeyaml:2.0") testImplementation(kotlin("test")) - testImplementation("com.android.tools.build:gradle:8.9.1") + testImplementation("com.android.tools.build:gradle:8.11.1") testImplementation("org.mockito:mockito-core:5.8.0") testImplementation("io.mockk:mockk:1.13.16") } diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt index 34dc19a7114e1..d6fc07c8d988a 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt @@ -19,11 +19,8 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.UnknownTaskException -import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.api.file.Directory -import org.gradle.api.plugins.PluginContainer import org.gradle.api.tasks.Copy -import org.gradle.api.tasks.TaskInstantiationException import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Jar import org.gradle.internal.os.OperatingSystem @@ -101,7 +98,6 @@ class FlutterPlugin : Plugin { repositories.maven { url = uri(repository!!) } - maybeAddAndroidStudioNativeConfiguration(plugins, dependencies) } project.apply { @@ -329,23 +325,19 @@ class FlutterPlugin : Plugin { } private fun addTaskForLockfileGeneration(rootProject: Project) { - try { - rootProject.tasks.register("generateLockfiles") { - doLast { - rootProject.subprojects.forEach { subproject -> - val gradlew: String = - getExecutableNameForPlatform("${rootProject.projectDir}/gradlew") - val execOps = rootProject.serviceOf() - execOps.exec { - workingDir(rootProject.projectDir) - executable(gradlew) - args(":${subproject.name}:dependencies", "--write-locks") - } + rootProject.tasks.register("generateLockfiles") { + doLast { + rootProject.subprojects.forEach { subproject -> + val gradlew: String = + getExecutableNameForPlatform("${rootProject.projectDir}/gradlew") + val execOps = rootProject.serviceOf() + execOps.exec { + workingDir(rootProject.projectDir) + executable(gradlew) + args(":${subproject.name}:dependencies", "--write-locks") } } } - } catch (e: TaskInstantiationException) { - // ignored } } @@ -821,19 +813,4 @@ class FlutterPlugin : Plugin { * This property is set by Android Studio when it invokes a Gradle task. */ private fun isInvokedFromAndroidStudio(): Boolean = project?.hasProperty("android.injected.invoked.from.ide") == true - - private fun shouldAddAndroidStudioNativeConfiguration(plugins: PluginContainer): Boolean = - plugins.hasPlugin("com.android.application") && isInvokedFromAndroidStudio() - - private fun maybeAddAndroidStudioNativeConfiguration( - plugins: PluginContainer, - dependencies: DependencyHandler - ) { - if (shouldAddAndroidStudioNativeConfiguration(plugins)) { - dependencies.add("compileOnly", "io.flutter:flutter_embedding_debug:$engineVersion") - dependencies.add("compileOnly", "io.flutter:armeabi_v7a_debug:$engineVersion") - dependencies.add("compileOnly", "io.flutter:arm64_v8a_debug:$engineVersion") - dependencies.add("compileOnly", "io.flutter:x86_64_debug:$engineVersion") - } - } } diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt index f9525ef479e31..4cc13207211cb 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt @@ -19,7 +19,7 @@ object FlutterPluginConstants { const val INTERMEDIATES_DIR = "intermediates" const val FLUTTER_STORAGE_BASE_URL = "FLUTTER_STORAGE_BASE_URL" - const val DEFAULT_MAVEN_HOST = "https://storage.googleapis.com" + const val DEFAULT_MAVEN_HOST = "https://download.shorebird.dev" /** Maps platforms to ABI architectures. */ @JvmStatic val PLATFORM_ARCH_MAP = diff --git a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt index 3da4623b9f71f..8ccc07a766307 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt @@ -14,9 +14,11 @@ import com.flutter.gradle.FlutterPluginUtils.getCompileSdkFromProject import com.flutter.gradle.FlutterPluginUtils.isBuiltAsApp import com.flutter.gradle.FlutterPluginUtils.supportsBuildMode import com.flutter.gradle.NativePluginLoaderReflectionBridge +import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.extraProperties import java.io.File +import com.android.build.gradle.internal.dsl.BuildType as dslBuildType /** * Handles interactions with the flutter plugins (not Gradle plugins) used by the Flutter project, @@ -181,7 +183,8 @@ class PluginHandler( // However, only copy if the plugin is also an app project, since library projects // cannot have applicationIdSuffix and other app-specific properties. if (isBuiltAsApp(pluginProject)) { - getAndroidExtension(pluginProject).buildTypes.addAll(getAndroidExtension(project).buildTypes) + (getAndroidExtension(pluginProject).buildTypes as NamedDomainObjectContainer) + .addAll(getAndroidExtension(project).buildTypes as NamedDomainObjectContainer) } else { // For library projects, create compatible build types without app-specific properties getAndroidExtension(project).buildTypes.forEach { appBuildType -> diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index c2d83d7ac4850..c8d3af4d27c41 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -46,6 +46,9 @@ Future run( args.removeWhere((String option) => option == '-vv' || option == '-v' || option == '--verbose'); } + // Reset this on each run to ensure we don't leak state across tests. + _alreadyHandlingToolError = null; + final bool usingLocalEngine = args.any((a) => a.startsWith('--local-engine')); return runInContext(() async { @@ -149,6 +152,13 @@ Future run( }, overrides: overrides); } +/// Track if we're actively processing an error so we don't try and process +/// additional asynchronous exceptions while we're trying to shut down. +/// +/// NOTE: This state is cleared at the beginning of [run] to ensure state +/// doesn't leak when running tests. +Future? _alreadyHandlingToolError; + Future _handleToolError( Object error, StackTrace? stackTrace, @@ -159,6 +169,30 @@ Future _handleToolError( ShutdownHooks shutdownHooks, { required bool usingLocalEngine, required FeatureFlags featureFlags, +}) async { + return _alreadyHandlingToolError ??= _handleToolErrorImpl( + error, + stackTrace, + verbose, + args, + reportCrashes, + getFlutterVersion, + shutdownHooks, + usingLocalEngine: usingLocalEngine, + featureFlags: featureFlags, + ); +} + +Future _handleToolErrorImpl( + Object error, + StackTrace? stackTrace, + bool verbose, + List args, + bool reportCrashes, + String Function() getFlutterVersion, + ShutdownHooks shutdownHooks, { + required bool usingLocalEngine, + required FeatureFlags featureFlags, }) async { if (error is UsageException) { globals.printError('${error.message}\n'); diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index d19732120c3c3..2813a7ea0696c 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -15,6 +15,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/utils.dart'; import '../build_info.dart'; import '../convert.dart'; import '../device.dart'; @@ -1119,12 +1120,12 @@ class AdbLogReader extends DeviceLogReader { // see: https://github.com/flutter/flutter/pull/8864. const decoder = Utf8Decoder(reportErrors: false); _adbProcess.stdout - .transform(decoder) - .transform(const LineSplitter()) + .transformWithCallSite(decoder) + .transform(const LineSplitter()) .listen(_onLine); _adbProcess.stderr - .transform(decoder) - .transform(const LineSplitter()) + .transformWithCallSite(decoder) + .transform(const LineSplitter()) .listen(_onLine); unawaited( _adbProcess.exitCode.whenComplete(() { diff --git a/packages/flutter_tools/lib/src/android/android_emulator.dart b/packages/flutter_tools/lib/src/android/android_emulator.dart index 126a7d5cd6afa..e25304cf10152 100644 --- a/packages/flutter_tools/lib/src/android/android_emulator.dart +++ b/packages/flutter_tools/lib/src/android/android_emulator.dart @@ -11,7 +11,7 @@ import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; -import '../convert.dart'; +import '../base/utils.dart'; import '../device.dart'; import '../emulator.dart'; import 'android_sdk.dart'; @@ -159,12 +159,10 @@ class AndroidEmulator extends Emulator { final stdoutList = []; final stderrList = []; final StreamSubscription stdoutSubscription = process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen(stdoutList.add); final StreamSubscription stderrSubscription = process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen(stderrList.add); final Future stdioFuture = Future.wait(>[ stdoutSubscription.asFuture(), diff --git a/packages/flutter_tools/lib/src/android/gradle_errors.dart b/packages/flutter_tools/lib/src/android/gradle_errors.dart index 77f7f7384666d..91122b13f3a3c 100644 --- a/packages/flutter_tools/lib/src/android/gradle_errors.dart +++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart @@ -83,6 +83,8 @@ final gradleErrors = [ usageOfV1EmbeddingReferencesHandler, jlinkErrorWithJava21AndSourceCompatibility, missingNdkSourcePropertiesFile, + applyingKotlinAndroidPluginErrorHandler, + useNewAgpDslErrorHandler, incompatibleKotlinVersionHandler, // This handler should always be last, as its key log output is sometimes in error messages with other root causes. ]; @@ -660,3 +662,52 @@ final missingNdkSourcePropertiesFile = GradleHandledError( }, eventLabel: 'ndk-missing-source-properties-file', ); + +/// Handler when applying the kotlin-android plugin results in a build failure. This failure occurs when +/// using AGP 9+ because built-in Kotlin has become the default behavior. +@visibleForTesting +final applyingKotlinAndroidPluginErrorHandler = GradleHandledError( + test: (String line) { + return line.contains( + "The 'org.jetbrains.kotlin.android' plugin is no longer required for Kotlin support since AGP 9.0", + ); + }, + handler: + ({required String line, required FlutterProject project, required bool usesAndroidX}) async { + final File appGradleFile = project.android.appGradleFile; + globals.printBox( + ''' +${globals.logger.terminal.warningMark} Starting AGP 9+, the default has become built-in Kotlin. This results in a build failure when applying the kotlin-android plugin at ${appGradleFile.path}. +\nTo resolve this, migrate to built-in Kotlin. For instructions on how to migrate, see: https://docs.flutter.dev/release/breaking-changes/migrate-to-agp-9''', + title: _boxTitle, + ); + + return GradleBuildStatus.exit; + }, + eventLabel: 'applying-kotlin-android-plugin-error', +); + +/// Handler when using the new AGP DSL interfaces. Starting AGP 9+, only the new +/// DSL interfaces are used. This results in a failure because we still depend +/// on old DSL types. +@visibleForTesting +final useNewAgpDslErrorHandler = GradleHandledError( + test: _lineMatcher(const [ + "> Failed to apply plugin 'dev.flutter.flutter-gradle-plugin'", + '> java.lang.NullPointerException (no error message)', + ]), + handler: + ({required String line, required FlutterProject project, required bool usesAndroidX}) async { + final File appGradleFile = project.android.appGradleFile; + globals.printBox( + ''' +${globals.logger.terminal.warningMark} Starting AGP 9+, only the new DSL interface will be read. This results in a build failure when applying the Flutter Gradle plugin at ${appGradleFile.path}. +\nTo resolve this update flutter or opt out of `android.newDsl`. For instructions on how to opt out, see: https://docs.flutter.dev/release/breaking-changes/migrate-to-agp-9 +\nIf you are not upgrading to AGP 9+, run `flutter analyze --suggestions` to check for incompatible dependencies.''', + title: _boxTitle, + ); + + return GradleBuildStatus.exit; + }, + eventLabel: 'use-new-agp-dsl-error', +); diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index 8f914c6cb21de..3581f86adc412 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -30,17 +30,17 @@ import 'android_sdk.dart'; // Please see the README before changing any of these values. // See https://gradle.org/releases -const templateDefaultGradleVersion = '8.12'; +const templateDefaultGradleVersion = '8.14'; // When bumping, also update: // * AGP version constants in packages/flutter_tools/gradle/build.gradle.kts // * AGP test constants in packages/flutter_tools/gradle/src/test/kotlin/DependencyVersionCheckerTest.kt // See https://mvnrepository.com/artifact/com.android.tools.build/gradle -const templateAndroidGradlePluginVersion = '8.9.1'; -const templateAndroidGradlePluginVersionForModule = '8.9.1'; +const templateAndroidGradlePluginVersion = '8.11.1'; +const templateAndroidGradlePluginVersionForModule = '8.11.1'; // See https://kotlinlang.org/docs/releases.html#release-details -const templateKotlinGradlePluginVersion = '2.1.0'; +const templateKotlinGradlePluginVersion = '2.2.20'; // The Flutter Gradle Plugin is only applied to app projects, and modules that // are built from source using (`include_flutter.groovy`). The remaining @@ -88,6 +88,12 @@ const maxKnownAndSupportedKgpVersion = '2.2.20'; @visibleForTesting const maxKnownAndSupportedAgpVersion = '9.0'; +// Update this when new versions of AGP with Kotlin support come out. +// +// Supported here means supported by the tooling for +// flutter analyze --suggestions and does not imply broader flutter support. +const maxKnownAgpVersionWithFullKotlinSupport = '8.11.1'; + // Update this when new versions of AGP come out. const maxKnownAgpVersion = '9.0'; @@ -650,7 +656,6 @@ bool validateAgpAndKgp(Logger logger, {required String? kgpV, required String? a 'AGP version ($agpV) older than oldest supported $oldestConsideredAgpVersion.', ); } - const maxKnownAgpVersionWithFullKotinSupport = '8.7.2'; if (isWithinVersionRange( kgpV, @@ -660,7 +665,7 @@ bool validateAgpAndKgp(Logger logger, {required String? kgpV, required String? a ) || isWithinVersionRange( agpV, - min: maxKnownAgpVersionWithFullKotinSupport, + min: maxKnownAgpVersionWithFullKotlinSupport, max: '100.100', inclusiveMin: false, )) { diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index 4551708cbfe59..d9398f9f07051 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -8,7 +8,6 @@ import '../artifacts.dart'; import '../build_info.dart'; import '../darwin/darwin.dart'; import '../macos/xcode.dart'; - import 'file_system.dart'; import 'logger.dart'; import 'process.dart'; @@ -136,7 +135,28 @@ class AOTSnapshotter { final Directory outputDir = _fileSystem.directory(outputPath); outputDir.createSync(recursive: true); - final genSnapshotArgs = ['--deterministic']; + // Currently we only use the linker on iOS, but we will eventually split out + // the concept of "optimizes patch snapshot" from "uses linker" and probably + // only uses the linker on iOS, but optimize patch snapshots everywhere. + // TODO(eseidel): TargetPlatform.darwin doesn't use the linker. + bool usesLinker = (platform == TargetPlatform.ios || platform == TargetPlatform.darwin); + final dumpLinkInfoArgs = [ + // Shorebird dumps the class table information during snapshot compilation which is later used during linking. + '--print_class_table_link_debug_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.class_table.json')}', + '--print_class_table_link_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.ct.link')}', + '--print_field_table_link_debug_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.field_table.json')}', + '--print_field_table_link_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.ft.link')}', + '--print_dispatch_table_link_debug_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.dispatch_table.json')}', + '--print_dispatch_table_link_info_to=${_fileSystem.path.join(outputDir.parent.path, 'App.dt.link')}', + ]; + + final genSnapshotArgs = [ + // Shorebird uses --deterministic to improve snapshot stability and increase linking. + '--deterministic', + // Only save LinkInfo if we're using the linker. + if (usesLinker) + ...dumpLinkInfoArgs, + ]; final bool targetingApplePlatform = platform == TargetPlatform.ios || platform == TargetPlatform.darwin; diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart index 5e8fabf119c58..187f5bfa8b728 100644 --- a/packages/flutter_tools/lib/src/base/process.dart +++ b/packages/flutter_tools/lib/src/base/process.dart @@ -13,6 +13,7 @@ import 'async_guard.dart'; import 'exit.dart'; import 'io.dart'; import 'logger.dart'; +import 'utils.dart'; typedef StringConverter = String? Function(String string); @@ -561,8 +562,7 @@ class _DefaultProcessUtils implements ProcessUtils { environment: environment, ); final StreamSubscription stdoutSubscription = process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .where((String line) => filter == null || filter.hasMatch(line)) .listen((String line) { String? mappedLine = line; @@ -581,8 +581,7 @@ class _DefaultProcessUtils implements ProcessUtils { } }); final StreamSubscription stderrSubscription = process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .where((String line) => filter == null || filter.hasMatch(line)) .listen((String line) { String? mappedLine = line; diff --git a/packages/flutter_tools/lib/src/base/utils.dart b/packages/flutter_tools/lib/src/base/utils.dart index 043a80143c1c9..43bb34d5910c7 100644 --- a/packages/flutter_tools/lib/src/base/utils.dart +++ b/packages/flutter_tools/lib/src/base/utils.dart @@ -12,6 +12,7 @@ import 'package:file/file.dart'; import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; // flutter_ignore: package_path_import +import 'package:stack_trace/stack_trace.dart'; import '../convert.dart'; import 'platform.dart'; @@ -580,3 +581,26 @@ extension UriExtension on Uri { return Uri(scheme: scheme, userInfo: userInfo, host: host, port: port, path: this.path); } } + +extension StackTraceTransform on Stream { + /// A custom implementation of [transform] that captures the + /// stack trace at the point of invocation. + Stream transformWithCallSite(StreamTransformer transformer) { + // Don't include this frame with the stack trace as it adds no value. + final callSiteTrace = Trace.current(1); + return transform(transformer).transform( + StreamTransformer.fromHandlers( + handleData: (data, sink) { + sink.add(data); + }, + handleError: (error, stackTrace, sink) { + sink.addError(error, callSiteTrace); + }, + ), + ); + } +} + +final utf8LineDecoder = StreamTransformer, String>.fromBind( + (stream) => stream.transformWithCallSite(utf8.decoder).transform(const LineSplitter()), +); diff --git a/packages/flutter_tools/lib/src/build_system/build_system.dart b/packages/flutter_tools/lib/src/build_system/build_system.dart index 0146558ea2332..3bc18a54368ef 100644 --- a/packages/flutter_tools/lib/src/build_system/build_system.dart +++ b/packages/flutter_tools/lib/src/build_system/build_system.dart @@ -447,6 +447,28 @@ class Environment { required this.generateDartPluginRegistry, }); + Environment copyWith({Directory? outputDir}) { + return Environment._( + outputDir: outputDir ?? this.outputDir, + projectDir: projectDir, + packageConfigPath: packageConfigPath, + buildDir: buildDir, + rootBuildDir: rootBuildDir, + cacheDir: cacheDir, + defines: defines, + flutterRootDir: flutterRootDir, + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + platform: platform, + analytics: analytics, + engineVersion: engineVersion, + inputs: inputs, + generateDartPluginRegistry: generateDartPluginRegistry, + ); + } + /// The [Source] value which is substituted with the path to [projectDir]. static const kProjectDirectory = '{PROJECT_DIR}'; diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart index be7cef8103597..d5256761bd69f 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart @@ -13,6 +13,7 @@ import '../../dart/package_map.dart'; import '../../devfs.dart'; import '../../flutter_manifest.dart'; import '../../isolated/native_assets/dart_hook_result.dart'; +import '../../shorebird/shorebird_yaml.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -162,6 +163,17 @@ Future copyAssets( } if (doCopy) { await (content.file as File).copy(file.path); + if (file.basename == 'shorebird.yaml') { + try { + updateShorebirdYaml( + environment.defines[kFlavor], + file.path, + environment: environment.platform.environment, + ); + } on Exception catch (error) { + throw Exception('Failed to generate shorebird configuration. Error: $error'); + } + } } } else { await file.writeAsBytes(await entry.value.content.contentsAsBytes()); diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 63eb1c736e825..e67e646bebf1b 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -504,3 +504,38 @@ abstract final class Lipo { } } } + +/// For managing the supplementary linking files for Shorebird. +abstract final class LinkSupplement { + static Future create( + Environment environment, { + required String inputBuildDir, + required String outputBuildDir, + }) async { + // If the shorebird directory exists, delete it first. + final Directory shorebirdDir = environment.fileSystem.directory( + environment.fileSystem.path.join(outputBuildDir, 'shorebird'), + ); + if (shorebirdDir.existsSync()) { + shorebirdDir.deleteSync(recursive: true); + } + + void maybeCopy(String name) { + final File file = environment.fileSystem.file( + environment.fileSystem.path.join(inputBuildDir, name), + ); + if (file.existsSync()) { + file.copySync(environment.fileSystem.path.join(shorebirdDir.path, name)); + } + } + + // Copy the link information (generated by gen_snapshot) + // into the shorebird directory. + maybeCopy('App.ct.link'); + maybeCopy('App.class_table.json'); + maybeCopy('App.dt.link'); + maybeCopy('App.dispatch_table.json'); + maybeCopy('App.ft.link'); + maybeCopy('App.field_table.json'); + } +} diff --git a/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart b/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart index 6103018621aa7..95d03f35426cf 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:meta/meta.dart'; + import '../../asset.dart'; import '../../base/logger.dart' show Logger; import '../../build_info.dart'; @@ -14,6 +16,9 @@ import 'native_assets.dart' show DartBuild; class FlutterHookRunnerNative implements FlutterHookRunner { FlutterHookResult? _flutterHookResult; + @visibleForTesting + static const kHooksOutputDirectory = 'native_hooks'; + @override Future runHooks({ required TargetPlatform targetPlatform, @@ -21,15 +26,25 @@ class FlutterHookRunnerNative implements FlutterHookRunner { Logger? logger, }) async { logger?.printTrace('runHooks() with ${environment.defines} and $targetPlatform'); - if (_flutterHookResult != null && !_flutterHookResult!.hasAnyModifiedFiles(globals.fs)) { + if (_flutterHookResult != null && + !_flutterHookResult!.hasAnyModifiedFiles(environment.fileSystem)) { logger?.printTrace('runHooks() - up-to-date already'); return _flutterHookResult!; } logger?.printTrace('runHooks() - will perform dart build'); + // Use a clone of the environment with a different output directory + // to avoid conflicts with the primary build's outputs. + final String outputDirPath = environment.fileSystem.path.join( + environment.outputDir.path, + kHooksOutputDirectory, + ); + final Environment hooksEnvironment = environment.copyWith( + outputDir: environment.fileSystem.directory(outputDirPath), + ); final BuildResult lastBuild = await globals.buildSystem.build( DartBuild(specifiedTargetPlatform: targetPlatform), - environment, + hooksEnvironment, ); if (!lastBuild.success) { for (final ExceptionMeasurement exceptionMeasurement in lastBuild.exceptions.values) { diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 3b70fc732b790..3bc5496799a9d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -143,6 +143,12 @@ abstract class AotAssemblyBase extends Target { // Don't fail if the dSYM wasn't created (i.e. during a debug build). skipMissingInputs: true, ); + + await LinkSupplement.create( + environment, + inputBuildDir: buildOutputPath, + outputBuildDir: getIosBuildDirectory(), + ); } } diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index d4693d9952fc8..4656d6aef0ceb 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -346,6 +346,12 @@ class CompileMacOSFramework extends Target { // Don't fail if the dSYM wasn't created (i.e. during a debug build). skipMissingInputs: true, ); + + await LinkSupplement.create( + environment, + inputBuildDir: buildOutputPath, + outputBuildDir: getMacOSBuildDirectory(), + ); } @override diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 03f3f6abf5db6..2941be08d24cc 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -34,6 +34,7 @@ import 'base/user_messages.dart'; import 'convert.dart'; import 'features.dart'; +const kShorebirdStorageUrl = 'https://download.shorebird.dev'; const kFlutterRootEnvironmentVariableName = 'FLUTTER_ROOT'; // should point to //flutter/ (root of flutter/flutter repo) const kFlutterEngineEnvironmentVariableName = @@ -517,7 +518,7 @@ class Cache { /// The base for URLs that store Flutter engine artifacts that are fetched /// during the installation of the Flutter SDK. /// - /// By default the base URL is https://storage.googleapis.com. However, if + /// By default the base URL is https://download.shorebird.dev. However, if /// `FLUTTER_STORAGE_BASE_URL` environment variable ([kFlutterStorageBaseUrl]) /// is provided, the environment variable value is returned instead. /// @@ -529,9 +530,13 @@ class Cache { String? overrideUrl = _platform.environment[kFlutterStorageBaseUrl]; if (overrideUrl == null) { return storageRealm.isEmpty - ? 'https://storage.googleapis.com' + ? 'https://download.shorebird.dev' : 'https://storage.googleapis.com/$storageRealm'; } + // Shorebird's artifact proxy is a trusted source. + if (overrideUrl == kShorebirdStorageUrl) { + return overrideUrl; + } // verify that this is a valid URI. overrideUrl = storageRealm.isEmpty ? overrideUrl : '$overrideUrl/$storageRealm'; try { diff --git a/packages/flutter_tools/lib/src/commands/assemble.dart b/packages/flutter_tools/lib/src/commands/assemble.dart index ffc4e9048c48d..2e7b11ad1e500 100644 --- a/packages/flutter_tools/lib/src/commands/assemble.dart +++ b/packages/flutter_tools/lib/src/commands/assemble.dart @@ -249,7 +249,7 @@ class AssembleCommand extends FlutterCommand { output = globals.fs.path.join(_flutterProject.directory.path, output); } final Artifacts artifacts = globals.artifacts!; - final result = Environment( + return Environment( outputDir: globals.fs.directory(output), buildDir: _flutterProject.directory .childDirectory('.dart_tool') @@ -269,12 +269,14 @@ class AssembleCommand extends FlutterCommand { engineVersion: artifacts.usesLocalArtifacts ? null : globals.flutterVersion.engineRevision, generateDartPluginRegistry: true, ); - return result; } Map _parseDefines(List values) { final results = {}; for (final chunk in values) { + if (chunk.isEmpty) { + continue; + } final int indexEquals = chunk.indexOf('='); if (indexEquals == -1) { throwToolExit('Improperly formatted define flag: $chunk'); diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 431e6b65daaa6..b150c4e5c327a 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -33,6 +33,7 @@ import '../run_cold.dart'; import '../run_hot.dart'; import '../runner/flutter_command.dart'; import '../runner/flutter_command_runner.dart'; +import '../vmservice.dart'; /// A Flutter-command that attaches to applications that have been launched /// without `flutter run`. @@ -253,180 +254,18 @@ known, it can be explicitly provided to attach via the command-line, e.g. @override Future runCommand() async { - await _validateArguments(); - final Device? device = await findTargetDevice(); if (device == null) { throwToolExit('Did not find any valid target devices.'); } - await _attachToDevice(device); - - return FlutterCommandResult.success(); - } - - Future _attachToDevice(Device device) async { - final FlutterProject flutterProject = FlutterProject.current(); - - final Daemon? daemon = boolArg('machine') - ? Daemon( - DaemonConnection( - daemonStreams: DaemonStreams.fromStdio(_stdio, logger: _logger), - logger: _logger, - ), - notifyingLogger: (_logger is NotifyingLogger) - ? _logger - : NotifyingLogger(verbose: _logger.isVerbose, parent: _logger), - logToStdout: true, - ) - : null; - - Stream? vmServiceUri; - final bool usesIpv6 = ipv6!; - final String ipv6Loopback = InternetAddress.loopbackIPv6.address; - final String ipv4Loopback = InternetAddress.loopbackIPv4.address; - final hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback; - final bool isWirelessIOSDevice = (device is IOSDevice) && device.isWirelesslyConnected; - - if ((debugPort == null && debugUri == null) || isWirelessIOSDevice) { - // The device port we expect to have the debug port be listening - final int? devicePort = debugPort ?? debugUri?.port ?? deviceVmservicePort; - - final VMServiceDiscoveryForAttach vmServiceDiscovery = device.getVMServiceDiscoveryForAttach( - appId: appId, - fuchsiaModule: stringArg('module'), - filterDevicePort: devicePort, - expectedHostPort: hostVmservicePort, - ipv6: usesIpv6, - logger: _logger, - ); - - _logger.printStatus('Waiting for a connection from Flutter on ${device.displayName}...'); - final Status discoveryStatus = _logger.startSpinner( - timeout: const Duration(seconds: 30), - slowWarningCallback: () { - // On iOS we rely on mDNS to find Dart VM Service. - if (device is IOSSimulator) { - // mDNS on simulators stopped working in macOS 15.4. - // See https://github.com/flutter/flutter/issues/166333. - return 'The Dart VM Service was not discovered after 30 seconds. ' - 'This may be due to limited mDNS support in the iOS Simulator.\n\n' - 'Click "Allow" to the prompt on your device asking if you would like to find and connect devices on your local network. ' - 'If you selected "Don\'t Allow", you can turn it on in Settings > Your App Name > Local Network. ' - "If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again.\n\n" - 'If you do not receive a prompt, either run "flutter attach" before starting the ' - 'app or use the Dart VM service URL from the Xcode console with ' - '"flutter attach --debug-url=".\n'; - } else if (_isIOSDevice(device)) { - // Remind the user to allow local network permissions on the device. - return 'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...\n\n' - 'Click "Allow" to the prompt on your device asking if you would like to find and connect devices on your local network. ' - 'If you selected "Don\'t Allow", you can turn it on in Settings > Your App Name > Local Network. ' - "If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again.\n"; - } - - return 'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...\n'; - }, - warningColor: TerminalColor.cyan, - ); - - vmServiceUri = vmServiceDiscovery.uris; - - // Stop the timer once we receive the first uri. - vmServiceUri = streamWithCallbackOnFirstItem(vmServiceUri, () => discoveryStatus.stop()); - } else { - vmServiceUri = Stream.fromFuture( - buildVMServiceUri( - device, - debugUri?.host ?? hostname, - debugPort ?? debugUri!.port, - hostVmservicePort, - debugUri?.path, - ), - ).asBroadcastStream(); - } - - _terminal.usesTerminalUi = daemon == null; + final bool machineMode = boolArg(FlutterGlobalOptions.kMachineFlag); try { - int? result; - if (daemon != null) { - final ResidentRunner runner = await createResidentRunner( - vmServiceUris: vmServiceUri, - device: device, - flutterProject: flutterProject, - usesIpv6: usesIpv6, - ); - late AppInstance app; - try { - app = await daemon.appDomain.launch( - runner, - ({ - Completer? connectionInfoCompleter, - Completer? appStartedCompleter, - }) { - return runner.attach( - connectionInfoCompleter: connectionInfoCompleter, - appStartedCompleter: appStartedCompleter, - ); - }, - device, - null, - true, - _fileSystem.currentDirectory, - LaunchMode.attach, - _logger as MachineOutputLogger, - ); - } on Exception catch (error) { - throwToolExit(error.toString()); - } - result = await app.runner.waitForAppToFinish(); - return; - } - while (true) { - final ResidentRunner runner = await createResidentRunner( - vmServiceUris: vmServiceUri, - device: device, - flutterProject: flutterProject, - usesIpv6: usesIpv6, - ); - final onAppStart = Completer.sync(); - TerminalHandler? terminalHandler; - unawaited( - onAppStart.future.whenComplete(() { - terminalHandler = - TerminalHandler( - runner, - logger: _logger, - terminal: _terminal, - signals: _signals, - processInfo: _processInfo, - reportReady: boolArg('report-ready'), - pidFile: stringArg('pid-file'), - ) - ..registerSignalHandlers() - ..setupTerminal(); - }), - ); - result = await runner.attach(appStartedCompleter: onAppStart); - if (result != 0) { - throwToolExit(null, exitCode: result); - } - terminalHandler?.stop(); - assert(result != null); - if (runner.exited || !runner.isWaitingForVmService) { - break; - } - _logger.printStatus( - 'Waiting for a new connection from Flutter on ' - '${device.displayName}...', - ); - } + await (machineMode ? _attachDaemon(device: device) : _attach(device: device)); } on RPCError catch (err) { - if (err.code == RPCErrorKind.kServiceDisappeared.code || - err.code == RPCErrorKind.kConnectionDisposed.code || - err.message.contains('Service connection disposed')) { + if (err.isConnectionDisposedException) { throwToolExit('Lost connection to device.'); } rethrow; @@ -439,14 +278,80 @@ known, it can be explicitly provided to attach via the command-line, e.g. // Do nothing, if the STDIN handle is no longer available, there is nothing actionable for us to do at this point } } + + return FlutterCommandResult.success(); + } + + Future _attach({required Device device}) async { + _terminal.usesTerminalUi = true; + final ResidentRunner runner = await _discoverVmServiceAndCreateResidentRunner(device: device); + final onAppStart = Completer.sync(); + TerminalHandler? terminalHandler; + unawaited( + onAppStart.future.whenComplete(() { + terminalHandler = + TerminalHandler( + runner, + logger: _logger, + terminal: _terminal, + signals: _signals, + processInfo: _processInfo, + reportReady: boolArg('report-ready'), + pidFile: stringArg('pid-file'), + ) + ..registerSignalHandlers() + ..setupTerminal(); + }), + ); + final int result = await runner.attach(appStartedCompleter: onAppStart); + if (result != 0) { + throwToolExit(null, exitCode: result); + } + terminalHandler?.stop(); + } + + Future _attachDaemon({required Device device}) async { + final daemon = Daemon( + DaemonConnection( + daemonStreams: DaemonStreams.fromStdio(_stdio, logger: _logger), + logger: _logger, + ), + notifyingLogger: (_logger is NotifyingLogger) + ? _logger + : NotifyingLogger(verbose: _logger.isVerbose, parent: _logger), + logToStdout: true, + ); + + final ResidentRunner runner = await _discoverVmServiceAndCreateResidentRunner(device: device); + late AppInstance app; + try { + app = await daemon.appDomain.launch( + runner, + ({ + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, + }) { + return runner.attach( + connectionInfoCompleter: connectionInfoCompleter, + appStartedCompleter: appStartedCompleter, + ); + }, + device, + null, + true, + _fileSystem.currentDirectory, + LaunchMode.attach, + _logger as MachineOutputLogger, + ); + } on Exception catch (error) { + throwToolExit(error.toString()); + } + await app.runner.waitForAppToFinish(); } - Future createResidentRunner({ - required Stream vmServiceUris, - required Device device, - required FlutterProject flutterProject, - required bool usesIpv6, - }) async { + Future _discoverVmServiceAndCreateResidentRunner({required Device device}) async { + final Stream vmServiceUri = _discoverVmService(device: device); + final BuildInfo buildInfo = await getBuildInfo(); final FlutterDevice flutterDevice = await FlutterDevice.create( @@ -457,7 +362,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. userIdentifier: userIdentifier, platform: _platform, ); - flutterDevice.vmServiceUris = vmServiceUris; + flutterDevice.vmServiceUris = vmServiceUri; final flutterDevices = [flutterDevice]; final debuggingOptions = DebuggingOptions.enabled( buildInfo, @@ -467,7 +372,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. usingCISystem: usingCISystem, debugLogsDirectoryPath: debugLogsDirectoryPath, enableDevTools: boolArg(FlutterCommand.kEnableDevTools), - ipv6: usesIpv6, + ipv6: ipv6!, printDtd: boolArg(FlutterGlobalOptions.kPrintDtd, global: true), ); @@ -479,7 +384,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. packagesFilePath: globalResults![FlutterGlobalOptions.kPackagesOption] as String?, projectRootPath: stringArg('project-root'), dillOutputPath: stringArg('output-dill'), - flutterProject: flutterProject, + flutterProject: FlutterProject.current(), nativeAssetsYamlFile: stringArg(FlutterOptions.kNativeAssetsYamlFile), analytics: analytics, logger: _logger, @@ -492,7 +397,69 @@ known, it can be explicitly provided to attach via the command-line, e.g. ); } - Future _validateArguments() async {} + Stream _discoverVmService({required Device device}) { + final bool usesIpv6 = ipv6!; + final String ipv6Loopback = InternetAddress.loopbackIPv6.address; + final String ipv4Loopback = InternetAddress.loopbackIPv4.address; + final hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback; + final bool isWirelessIOSDevice = (device is IOSDevice) && device.isWirelesslyConnected; + + if (!isWirelessIOSDevice && (debugPort != null || debugUri != null)) { + return Stream.fromFuture( + buildVMServiceUri( + device, + debugUri?.host ?? hostname, + debugPort ?? debugUri!.port, + hostVmservicePort, + debugUri?.path, + ), + ); + } + + // The device port we expect to have the debug port be listening + final int? devicePort = debugPort ?? debugUri?.port ?? deviceVmservicePort; + + final VMServiceDiscoveryForAttach vmServiceDiscovery = device.getVMServiceDiscoveryForAttach( + appId: appId, + fuchsiaModule: stringArg('module'), + filterDevicePort: devicePort, + expectedHostPort: hostVmservicePort, + ipv6: usesIpv6, + logger: _logger, + ); + + _logger.printStatus('Waiting for a connection from Flutter on ${device.displayName}...'); + final Status discoveryStatus = _logger.startSpinner( + timeout: const Duration(seconds: 30), + slowWarningCallback: () { + // On iOS we rely on mDNS to find Dart VM Service. + if (device is IOSSimulator) { + // mDNS on simulators stopped working in macOS 15.4. + // See https://github.com/flutter/flutter/issues/166333. + return 'The Dart VM Service was not discovered after 30 seconds. ' + 'This may be due to limited mDNS support in the iOS Simulator.\n\n' + 'Click "Allow" to the prompt on your device asking if you would like to find and connect devices on your local network. ' + 'If you selected "Don\'t Allow", you can turn it on in Settings > Your App Name > Local Network. ' + "If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again.\n\n" + 'If you do not receive a prompt, either run "flutter attach" before starting the ' + 'app or use the Dart VM service URL from the Xcode console with ' + '"flutter attach --debug-url=".\n'; + } else if (_isIOSDevice(device)) { + // Remind the user to allow local network permissions on the device. + return 'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...\n\n' + 'Click "Allow" to the prompt on your device asking if you would like to find and connect devices on your local network. ' + 'If you selected "Don\'t Allow", you can turn it on in Settings > Your App Name > Local Network. ' + "If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again.\n"; + } + + return 'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...\n'; + }, + warningColor: TerminalColor.cyan, + ); + + // Stop the timer once we receive the first uri. + return streamWithCallbackOnFirstItem(vmServiceDiscovery.uris, discoveryStatus.stop); + } bool _isIOSDevice(Device device) { return (device.platformType == PlatformType.ios) || (device is MacOSDesignedForIPadDevice); diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index d31d30fdcd9f7..31704fe4f53bd 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -888,7 +888,7 @@ class RunCommand extends RunCommandBase { }), ); try { - final int? result = await runner.run( + final int result = await runner.run( appStartedCompleter: appStartedTimeRecorder, route: route, ); diff --git a/packages/flutter_tools/lib/src/commands/symbolize.dart b/packages/flutter_tools/lib/src/commands/symbolize.dart index 92177ed878a85..54bc92d51a07d 100644 --- a/packages/flutter_tools/lib/src/commands/symbolize.dart +++ b/packages/flutter_tools/lib/src/commands/symbolize.dart @@ -11,6 +11,7 @@ import 'package:native_stack_traces/native_stack_traces.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; +import '../base/utils.dart'; import '../convert.dart'; import '../runner/flutter_command.dart'; @@ -175,7 +176,7 @@ class SymbolizeCommand extends FlutterCommand { output = outputFile.openWrite(); } else { final outputController = StreamController>(); - outputController.stream.transform(utf8.decoder).listen(_stdio.stdoutWrite); + outputController.stream.transformWithCallSite(utf8.decoder).listen(_stdio.stdoutWrite); output = IOSink(outputController); } @@ -299,9 +300,8 @@ class DwarfSymbolizationService { StreamSubscription? subscription; subscription = input .cast>() - .transform(const Utf8Decoder()) - .transform(const LineSplitter()) - .transform(unitSymbolsTransformer(unitSymbols)) + .transform(utf8LineDecoder) + .transformWithCallSite(unitSymbolsTransformer(unitSymbols)) .listen( (String line) { try { diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index d8cf24a3f3311..e3d556a931a7b 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -24,6 +24,7 @@ import '../bundle.dart' as bundle; import '../cache.dart'; import '../convert.dart'; import '../device.dart'; +import '../features.dart'; import '../globals.dart' as globals; import '../isolated/resident_web_runner.dart'; import '../project.dart'; @@ -111,7 +112,7 @@ abstract base class WidgetPreviewSubCommandBase extends FlutterCommand { FlutterProject validateFlutterProjectForPreview(Directory directory) { logger.printTrace('Verifying that ${directory.path} is a Flutter project.'); final FlutterProject flutterProject = projectFactory.fromDirectory(directory); - if (!flutterProject.dartTool.existsSync()) { + if (!flutterProject.pubspecFile.existsSync()) { throwToolExit('${flutterProject.directory.path} is not a valid Flutter project.'); } return flutterProject; @@ -234,7 +235,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C late final _previewDetector = PreviewDetector( platform: platform, previewAnalytics: previewAnalytics, - projectRoot: rootProject.directory, + project: rootProject, logger: logger, fs: fs, onChangeDetected: onChangeDetected, @@ -250,6 +251,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C ); late var _dtdService = WidgetPreviewDtdServices( + previewAnalytics: previewAnalytics, fs: fs, logger: logger, shutdownHooks: shutdownHooks, @@ -261,6 +263,14 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C /// The currently running instance of the widget preview scaffold. ResidentRunner? _widgetPreviewApp; + /// The location of the widget_preview_scaffold for the current execution of the command. + /// + /// This is only meant for testing as there's no simple mapping from the target project to the + /// scaffold project. + // TODO(bkonyi): remove once https://github.com/flutter/flutter/issues/179036 is resolved. + @visibleForTesting + static late Directory widgetPreviewScaffold; + @override Future runCommand() async { assert(_logger is WidgetPreviewMachineAwareLogger); @@ -270,7 +280,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C logger.sendInitializingEvent(); final String? customPreviewScaffoldOutput = stringArg(kWidgetPreviewScaffoldOutputDir); - final Directory widgetPreviewScaffold = customPreviewScaffoldOutput != null + widgetPreviewScaffold = customPreviewScaffoldOutput != null ? fs.directory(customPreviewScaffoldOutput) : rootProject.widgetPreviewScaffold; @@ -279,7 +289,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C final bool generateScaffoldProject = customPreviewScaffoldOutput != null || _previewManifest.shouldGenerateProject(); // TODO(bkonyi): can this be moved? - widgetPreviewScaffold.createSync(); + widgetPreviewScaffold.createSync(recursive: true); fs.currentDirectory = widgetPreviewScaffold; if (generateScaffoldProject) { @@ -316,8 +326,9 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C // after we generate the scaffold project as invoking the getter triggers // lazy initialization of the preview scaffold's FlutterManifest before // the scaffold project's pubspec has been generated. + final FlutterProject widgetPreviewScaffoldProject = rootProject.widgetPreviewScaffoldProject; _previewCodeGenerator = PreviewCodeGenerator( - widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject, + widgetPreviewScaffoldProject: widgetPreviewScaffoldProject, fs: fs, ); @@ -331,6 +342,12 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C await _previewPubspecBuilder.populatePreviewPubspec(rootProject: rootProject); } + if (!widgetPreviewScaffoldProject.dartTool.existsSync()) { + await _previewPubspecBuilder.generatePackageConfig( + widgetPreviewScaffoldProject: widgetPreviewScaffoldProject, + ); + } + shutdownHooks.addShutdownHook(() async { await _widgetPreviewApp?.exitApp(); await _previewDetector.dispose(); @@ -341,7 +358,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C await configureDtd(); final int result = await runPreviewEnvironment( - widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject, + widgetPreviewScaffoldProject: widgetPreviewScaffoldProject, ); if (result != 0) { throwToolExit('Failed to launch the widget previewer.', exitCode: result); @@ -384,10 +401,19 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C logger.printTrace('Connecting to existing DTD instance at: $existingDtdUri...'); await _dtdService.connect(dtdWsUri: existingDtdUri); } + _previewCodeGenerator.populateDtdConnectionInfo(_dtdService.dtdUri!); } Future runPreviewEnvironment({required FlutterProject widgetPreviewScaffoldProject}) async { try { + // In the rare case that Flutter Web is disabled, the device manager will not return any web + // devices which will cause us to crash. + if (!featureFlags.isWebEnabled) { + throwToolExit( + 'Widget Previews requires Flutter Web to be enabled. Please run ' + "'flutter config --enable-web' to enable Flutter Web and try again.", + ); + } final Device device; if (boolArg(kWebServer)) { final List devices; @@ -438,12 +464,6 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C BuildMode.debug, null, treeShakeIcons: false, - // Provide the DTD connection information directly to the preview scaffold. - // This could, in theory, be provided via a follow up call to a service extension - // registered by the preview scaffold, but there's some uncertainty around how service - // extensions will work with Flutter web embedded in VSCode without a Chrome debugger - // connection. - dartDefines: ['$kWidgetPreviewDtdUriEnvVar=${_dtdService.dtdUri}'], packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path, packageConfig: PackageConfig.parseBytes( widgetPreviewScaffoldProject.packageConfig.readAsBytesSync(), @@ -481,6 +501,15 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C platform: platform, outputPreferences: globals.outputPreferences, systemClock: globals.systemClock, + // Explicitly provide the project root path rather than relying on the current directory + // as the current directory exists within $TMP. At least on MacOS, when setting the + // current directory to the widget_preview_scaffold project created under + // `/var/folders/...`, the underlying chdir call actually changes the directory to + // `/private/var/folders/...`. These directories are identical, but confuse the package + // config resolution logic. + // TODO(bkonyi): consider removing if we stop placing the scaffold in $TMP. + // See https://github.com/flutter/flutter/issues/179036 + projectRootPath: widgetPreviewScaffoldProject.directory.absolute.path, ); unawaited(_widgetPreviewApp!.run(appStartedCompleter: appStarted)); await appStarted.future; diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 2aa8dea5b7f96..f28c557312aaa 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -17,6 +17,7 @@ import 'base/io.dart'; import 'base/logger.dart'; import 'base/platform.dart'; import 'base/process.dart'; +import 'base/utils.dart'; import 'build_info.dart'; import 'convert.dart'; @@ -378,10 +379,7 @@ class KernelCompiler { final Process server = await _processManager.start(command); server.stderr.transform(utf8.decoder).listen(_logger.printError); - server.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_stdoutHandler.handler); + server.stdout.transform(utf8LineDecoder).listen(_stdoutHandler.handler); final int exitCode = await server.exitCode; if (exitCode == 0) { return _stdoutHandler.compilerOutput?.future; @@ -890,8 +888,7 @@ class DefaultResidentCompiler implements ResidentCompiler { _logger.printTrace(command.join(' ')); _server = await _processManager.start(command); _server?.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen( _stdoutHandler.handler, onDone: () { @@ -904,10 +901,7 @@ class DefaultResidentCompiler implements ResidentCompiler { }, ); - _server?.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_logger.printError); + _server?.stderr.transform(utf8LineDecoder).listen(_logger.printError); unawaited( _server?.exitCode.then((int code) { diff --git a/packages/flutter_tools/lib/src/dart/analysis.dart b/packages/flutter_tools/lib/src/dart/analysis.dart index 4c2a3d614b2e4..e4bddf3ba4719 100644 --- a/packages/flutter_tools/lib/src/dart/analysis.dart +++ b/packages/flutter_tools/lib/src/dart/analysis.dart @@ -75,14 +75,10 @@ class AnalysisServer { // This callback hookup can't throw. unawaited(_process!.exitCode.whenComplete(() => _process = null)); - final Stream errorStream = _process!.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()); + final Stream errorStream = _process!.stderr.transform(utf8LineDecoder); errorStream.listen(_handleError); - final Stream inStream = _process!.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()); + final Stream inStream = _process!.stdout.transform(utf8LineDecoder); inStream.listen(_handleServerResponse); _sendCommand('server.setSubscriptions', { diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index c66b163d57703..a6b434a0edf05 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -72,6 +72,10 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile // that should be launched (including a flag for whether it has been // launched by the tool or needs launching by the editor). 'app.webLaunchUrl', + // app.warning is used to pass warnings that should be shown more + // prominently by clients (for example warning about slow wireless + // debugging). + 'app.warning', }; /// Completers for reverse requests from Flutter that may need to be handled by the client. diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart index c3e5bfe8292aa..a93354b7cd958 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart @@ -10,6 +10,7 @@ import 'package:vm_service/vm_service.dart' as vm; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/platform.dart'; +import '../base/utils.dart'; import '../cache.dart'; import '../convert.dart'; import 'flutter_adapter_args.dart'; @@ -165,8 +166,8 @@ abstract class FlutterBaseDebugAdapter }(executable, processArgs, env: env); this.process = process; - process.stdout.transform(ByteToLineTransformer()).listen(handleStdout); - process.stderr.transform(utf8.decoder).listen(handleStderr); + process.stdout.transformWithCallSite(ByteToLineTransformer()).listen(handleStdout); + process.stderr.transformWithCallSite(utf8.decoder).listen(handleStderr); unawaited(process.exitCode.then(handleExitCode)); } diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart index e080ac2faa810..e485068c73288 100644 --- a/packages/flutter_tools/lib/src/desktop_device.dart +++ b/packages/flutter_tools/lib/src/desktop_device.dart @@ -11,8 +11,8 @@ import 'base/file_system.dart'; import 'base/io.dart'; import 'base/logger.dart'; import 'base/os.dart'; +import 'base/utils.dart'; import 'build_info.dart'; -import 'convert.dart'; import 'devfs.dart'; import 'device.dart'; import 'device_port_forwarder.dart'; @@ -362,7 +362,7 @@ class DesktopLogReader extends DeviceLogReader { @override Stream get logLines { - return _inputController.stream.transform(utf8.decoder).transform(const LineSplitter()); + return _inputController.stream.transform(utf8LineDecoder); } @override diff --git a/packages/flutter_tools/lib/src/devtools_launcher.dart b/packages/flutter_tools/lib/src/devtools_launcher.dart index 23ff51ea8e986..24d4fd1667ce6 100644 --- a/packages/flutter_tools/lib/src/devtools_launcher.dart +++ b/packages/flutter_tools/lib/src/devtools_launcher.dart @@ -12,7 +12,7 @@ import 'base/bot_detector.dart'; import 'base/common.dart'; import 'base/io.dart' as io; import 'base/logger.dart'; -import 'convert.dart'; +import 'base/utils.dart'; import 'resident_runner.dart'; /// An implementation of the devtools launcher that uses `dart devtools` to @@ -66,9 +66,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher { _processStartCompleter.complete(); final devToolsCompleter = Completer(); - _devToolsProcess!.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen(( - String line, - ) { + _devToolsProcess!.stdout.transform(utf8LineDecoder).listen((String line) { final Match? dtdMatch = _serveDtdPattern.firstMatch(line); if (dtdMatch != null) { final String uri = dtdMatch[1]!; @@ -80,10 +78,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher { devToolsCompleter.complete(Uri.parse(url)); } }); - _devToolsProcess!.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_logger.printError); + _devToolsProcess!.stderr.transform(utf8LineDecoder).listen(_logger.printError); final bool runningOnBot = await _botDetector.isRunningOnBot; devToolsProcessExit = _devToolsProcess!.exitCode.then((int exitCode) { diff --git a/packages/flutter_tools/lib/src/http_host_validator.dart b/packages/flutter_tools/lib/src/http_host_validator.dart index 9702f83bffd08..8363221166398 100644 --- a/packages/flutter_tools/lib/src/http_host_validator.dart +++ b/packages/flutter_tools/lib/src/http_host_validator.dart @@ -11,7 +11,7 @@ import 'doctor_validator.dart'; import 'features.dart'; /// Common Flutter HTTP hosts. -const kCloudHost = 'https://storage.googleapis.com/'; +const kCloudHost = 'https://download.shorebird.dev/'; const kCocoaPods = 'https://cocoapods.org/'; const kGitHub = 'https://github.com/'; const kMaven = 'https://maven.google.com/'; diff --git a/packages/flutter_tools/lib/src/ios/application_package.dart b/packages/flutter_tools/lib/src/ios/application_package.dart index f1c8f44849548..e8613d4d7a8bd 100644 --- a/packages/flutter_tools/lib/src/ios/application_package.dart +++ b/packages/flutter_tools/lib/src/ios/application_package.dart @@ -130,6 +130,18 @@ class BuildableIOSApp extends IOSApp { @override String? get name => _appProductName; + String get shorebirdYamlPath => + globals.fs.path.join( + archiveBundleOutputPath, + 'Products', + 'Applications', + _appProductName != null ? '$_appProductName.app' : 'Runner.app', + 'Frameworks', + 'App.framework', + 'flutter_assets', + 'shorebird.yaml', + ); + @override String get simulatorBundlePath => _buildAppPath(XcodeSdk.IPhoneSimulator.platformName); diff --git a/packages/flutter_tools/lib/src/ios/core_devices.dart b/packages/flutter_tools/lib/src/ios/core_devices.dart index 8db15860a934d..6d9314ecd38b9 100644 --- a/packages/flutter_tools/lib/src/ios/core_devices.dart +++ b/packages/flutter_tools/lib/src/ios/core_devices.dart @@ -13,6 +13,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../base/template.dart'; +import '../base/utils.dart'; import '../convert.dart'; import '../device.dart'; import '../macos/xcode.dart'; @@ -334,6 +335,8 @@ class IOSCoreDeviceControl { 'Failed to execute code (error: EXC_BAD_ACCESS, debugger assist: not detected)', ]; + static const kCoreDeviceLaunchCompleteLog = 'Waiting for the application to terminate'; + /// Executes `devicectl` command to get list of devices. The command will /// likely complete before [timeout] is reached. If [timeout] is reached, /// the command will be stopped as a failure. @@ -622,13 +625,21 @@ class IOSCoreDeviceControl { /// /// If [attachToConsole] is true, attaches the application to the console and waits for the app /// to terminate. + /// + /// When [jsonOutputFile] is provided, devicectl will write a JSON file with the command results + /// after the command has completed. This will not have the results when using [attachToConsole] + /// until the process has exited. + /// + /// When [logOutputFile] is provided, devicectl will write all logging otherwise passed to + /// stdout/stderr to the file. It will also continue to stream the logs to stdout/stderr. List _launchAppCommand({ required String deviceId, required String bundleId, List launchArguments = const [], bool startStopped = false, bool attachToConsole = false, - File? outputFile, + File? jsonOutputFile, + File? logOutputFile, }) { return [ ..._xcode.xcrunCommand(), @@ -646,7 +657,8 @@ class IOSCoreDeviceControl { // See https://github.com/llvm/llvm-project/blob/19b43e1757b4fd3d0f188cf8a08e9febb0dbec2f/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp#L1227-L1233 '{"OS_ACTIVITY_DT_MODE": "enable"}', ], - if (outputFile != null) ...['--json-output', outputFile.path], + if (jsonOutputFile != null) ...['--json-output', jsonOutputFile.path], + if (logOutputFile != null) ...['--log-output', logOutputFile.path], bundleId, if (launchArguments.isNotEmpty) ...launchArguments, ]; @@ -675,7 +687,7 @@ class IOSCoreDeviceControl { deviceId: deviceId, launchArguments: launchArguments, startStopped: startStopped, - outputFile: output, + jsonOutputFile: output, ); try { @@ -726,6 +738,9 @@ class IOSCoreDeviceControl { return false; } + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('launch_log.txt')..createSync(); + final launchCompleter = Completer(); final List command = _launchAppCommand( bundleId: bundleId, @@ -733,15 +748,15 @@ class IOSCoreDeviceControl { launchArguments: launchArguments, startStopped: startStopped, attachToConsole: true, + logOutputFile: output, ); - + Timer? timer; try { final Process launchProcess = await _processUtils.start(command); coreDeviceLogForwarder.launchProcess = launchProcess; final StreamSubscription stdoutSubscription = launchProcess.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { if (launchCompleter.isCompleted && !_ignoreLog(line)) { coreDeviceLogForwarder.addLog(line); @@ -749,14 +764,13 @@ class IOSCoreDeviceControl { _logger.printTrace(line); } - if (line.contains('Waiting for the application to terminate')) { + if (!launchCompleter.isCompleted && line.contains(kCoreDeviceLaunchCompleteLog)) { launchCompleter.complete(true); } }); final StreamSubscription stderrSubscription = launchProcess.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { if (launchCompleter.isCompleted && !_ignoreLog(line)) { coreDeviceLogForwarder.addLog(line); @@ -779,10 +793,27 @@ class IOSCoreDeviceControl { } }), ); - return launchCompleter.future; + + // Sometimes devicectl launch logs don't stream to stdout. + // As a workaround, we also use the log output file to check if it has finished launching. + timer = Timer.periodic(const Duration(seconds: 1), (timer) async { + if (await output.exists()) { + final String contents = await output.readAsString(); + if (!launchCompleter.isCompleted && contents.contains(kCoreDeviceLaunchCompleteLog)) { + launchCompleter.complete(true); + } + } + }); + + // Do not return the launchCompleter.future directly, otherwise, the timer will be canceled + // prematurely. + final bool status = await launchCompleter.future; + return status; } on ProcessException catch (err) { _logger.printTrace('Error executing devicectl: $err'); return false; + } finally { + timer?.cancel(); } } diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index bbcca01aae9f9..0921ec7c5860d 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -494,6 +494,8 @@ class IOSDevice extends Device { ); } + warnIfSlowWirelessDebugging(debuggingOptions); + if (!prebuiltApplication) { _logger.printTrace('Building ${package.name} for $id'); @@ -774,6 +776,35 @@ class IOSDevice extends Device { } } + @visibleForTesting + void warnIfSlowWirelessDebugging(DebuggingOptions debuggingOptions) { + // The minimum iOS version where wireless debugging is known to be slow. + const minSlowWirelessDebugIOSVersion = 26; + final Version? sdkVersion = this.sdkVersion; + + if (!isWirelesslyConnected || + !debuggingOptions.debuggingEnabled || + sdkVersion == null || + sdkVersion.major < minSlowWirelessDebugIOSVersion) { + return; + } + + final warningMessage = + 'Wireless debugging on iOS ${sdkVersion.major} may be slower than expected. ' + 'For better performance, consider using a wired (USB) connection.'; + + _logger.printWarning(warningMessage); + + _logger.sendEvent('app.warning', { + 'warningId': 'ios-wireless-slow', + 'warning': warningMessage, + 'category': 'ios-wireless-performance', + 'deviceId': id, + 'deviceOsVersion': sdkVersion.major, + 'actionable': true, + }); + } + void _printInstallError(Directory bundle) { _logger.printError('Could not run ${bundle.path} on $id.'); _logger.printError('Try launching Xcode and selecting "Product > Run" to fix the problem:'); @@ -1666,14 +1697,8 @@ class IOSDeviceLogReader extends DeviceLogReader { return; } _iMobileDevice.startLogger(_deviceId, _isWirelesslyConnected).then((Process process) { - process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_newSyslogLineHandler()); - process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_newSyslogLineHandler()); + process.stdout.transform(utf8LineDecoder).listen(_newSyslogLineHandler()); + process.stderr.transform(utf8LineDecoder).listen(_newSyslogLineHandler()); process.exitCode.whenComplete(() { if (!linesController.hasListener) { return; diff --git a/packages/flutter_tools/lib/src/ios/ios_deploy.dart b/packages/flutter_tools/lib/src/ios/ios_deploy.dart index 2ec3210bb7e39..e9de491ad13da 100644 --- a/packages/flutter_tools/lib/src/ios/ios_deploy.dart +++ b/packages/flutter_tools/lib/src/ios/ios_deploy.dart @@ -13,8 +13,8 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/utils.dart'; import '../cache.dart'; -import '../convert.dart'; import '../device.dart'; import 'code_signing.dart'; @@ -316,158 +316,157 @@ class IOSDeployDebugger { try { _iosDeployProcess = await _processUtils.start(_launchCommand, environment: _iosDeployEnv); String? lastLineFromDebugger; - final StreamSubscription stdoutSubscription = _iosDeployProcess!.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - _monitorIOSDeployFailure(line, _logger); - - // (lldb) platform select remote-'ios' --sysroot - // Use the configurable custom lldb prompt in the regex. The developer can set this prompt to anything. - // For example `settings set prompt "(mylldb)"` in ~/.lldbinit results in: - // "(mylldb) platform select remote-'ios' --sysroot" - if (_lldbPlatformSelect.hasMatch(line)) { - final String platformSelect = _lldbPlatformSelect.stringMatch(line) ?? ''; - if (platformSelect.isEmpty) { - return; - } - final int promptEndIndex = line.indexOf(platformSelect); - if (promptEndIndex == -1) { - return; - } - final String prompt = line.substring(0, promptEndIndex); - lldbRun = RegExp(RegExp.escape(prompt) + r'\s*run'); - _logger.printTrace(line); - return; - } - - // Symbol Path: /Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols - if (_symbolsPathPattern.hasMatch(line)) { - _logger.printTrace('Detected path to iOS debug symbols: "$line"'); - final String prefix = _symbolsPathPattern.stringMatch(line) ?? ''; - if (prefix.isEmpty) { - return; - } - symbolsDirectoryPath = line.substring(prefix.length); - return; - } - - // (lldb) run - // success - // 2020-09-15 13:42:25.185474-0700 Runner[477:181141] flutter: The Dart VM service is listening on http://127.0.0.1:57782/ - if (lldbRun.hasMatch(line)) { - _logger.printTrace(line); - _debuggerState = _IOSDeployDebuggerState.launching; - return; - } - // Next line after "run" must be "success", or the attach failed. - // Example: "error: process launch failed" - if (_debuggerState == _IOSDeployDebuggerState.launching) { - _logger.printTrace(line); - final attachSuccess = line == 'success'; - _debuggerState = attachSuccess - ? _IOSDeployDebuggerState.attached - : _IOSDeployDebuggerState.detached; - if (!debuggerCompleter.isCompleted) { - debuggerCompleter.complete(attachSuccess); - } - return; - } - - // (lldb) process signal SIGSTOP - // or - // process signal SIGSTOP - if (line.contains(_signalStop)) { - // The app is about to be stopped. Only show in verbose mode. - _logger.printTrace(line); - return; - } - - // error: Failed to send signal 17: failed to send signal 17 - if (line.contains(_signalStopError)) { - // The stop signal failed, force exit. - exit(); - return; - } - - if (line == _backTraceAll) { - // The app is stopped and the backtrace for all threads will be printed. - _logger.printTrace(line); - // Even though we're not "detached", just stopped, mark as detached so the backtrace - // is only show in verbose. - _debuggerState = _IOSDeployDebuggerState.detached; - - // If we paused the app and are waiting to resume it, complete the completer - final Completer? processResumeCompleter = _processResumeCompleter; - if (processResumeCompleter != null) { - _processResumeCompleter = null; - processResumeCompleter.complete(); - } - return; - } - - if (line.contains('PROCESS_STOPPED') || _lldbProcessStopped.hasMatch(line)) { - // The app has been stopped. Dump the backtrace, and detach. - _logger.printTrace(line); - _iosDeployProcess?.stdin.writeln(_backTraceAll); - if (_processResumeCompleter == null) { - detach(); - } - return; - } - - if (line.contains('PROCESS_EXITED') || _lldbProcessExit.hasMatch(line)) { - // The app exited or crashed, so exit. Continue passing debugging - // messages to the log reader until it exits to capture crash dumps. - _logger.printTrace(line); - if (line.contains(_lostConnectionPattern)) { - _lostConnection = true; - } - exit(); - return; - } - if (_lldbProcessDetached.hasMatch(line)) { - // The debugger has detached from the app, and there will be no more debugging messages. - // Kill the ios-deploy process. - _logger.printTrace(line); - exit(); - return; - } - - if (_lldbProcessResuming.hasMatch(line)) { - _logger.printTrace(line); - // we marked this detached when we received [_backTraceAll] - _debuggerState = _IOSDeployDebuggerState.attached; - return; - } - - if (_debuggerState != _IOSDeployDebuggerState.attached) { - _logger.printTrace(line); - return; - } - if (lastLineFromDebugger != null && lastLineFromDebugger!.isNotEmpty && line.isEmpty) { - // The lldb console stream from ios-deploy is separated lines by an extra \r\n. - // To avoid all lines being double spaced, if the last line from the - // debugger was not an empty line, skip this empty line. - // This will still cause "legit" logged newlines to be doubled... - } else if (!_debuggerOutput.isClosed) { - _debuggerOutput.add(line); - - // Sometimes the `ios-deploy` process does not return logs from the - // application after attaching, such as the Dart VM url. In CI, - // `idevicesyslog` is used as a fallback to get logs. Print a - // message to indicate whether logs were received from `ios-deploy` - // to help with debugging. - if (!receivedLogs) { - _logger.printTrace('Received logs from ios-deploy.'); - receivedLogs = true; - } - } - lastLineFromDebugger = line; - }); + final StreamSubscription + stdoutSubscription = _iosDeployProcess!.stdout.transform(utf8LineDecoder).listen(( + String line, + ) { + _monitorIOSDeployFailure(line, _logger); + + // (lldb) platform select remote-'ios' --sysroot + // Use the configurable custom lldb prompt in the regex. The developer can set this prompt to anything. + // For example `settings set prompt "(mylldb)"` in ~/.lldbinit results in: + // "(mylldb) platform select remote-'ios' --sysroot" + if (_lldbPlatformSelect.hasMatch(line)) { + final String platformSelect = _lldbPlatformSelect.stringMatch(line) ?? ''; + if (platformSelect.isEmpty) { + return; + } + final int promptEndIndex = line.indexOf(platformSelect); + if (promptEndIndex == -1) { + return; + } + final String prompt = line.substring(0, promptEndIndex); + lldbRun = RegExp(RegExp.escape(prompt) + r'\s*run'); + _logger.printTrace(line); + return; + } + + // Symbol Path: /Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols + if (_symbolsPathPattern.hasMatch(line)) { + _logger.printTrace('Detected path to iOS debug symbols: "$line"'); + final String prefix = _symbolsPathPattern.stringMatch(line) ?? ''; + if (prefix.isEmpty) { + return; + } + symbolsDirectoryPath = line.substring(prefix.length); + return; + } + + // (lldb) run + // success + // 2020-09-15 13:42:25.185474-0700 Runner[477:181141] flutter: The Dart VM service is listening on http://127.0.0.1:57782/ + if (lldbRun.hasMatch(line)) { + _logger.printTrace(line); + _debuggerState = _IOSDeployDebuggerState.launching; + return; + } + // Next line after "run" must be "success", or the attach failed. + // Example: "error: process launch failed" + if (_debuggerState == _IOSDeployDebuggerState.launching) { + _logger.printTrace(line); + final attachSuccess = line == 'success'; + _debuggerState = attachSuccess + ? _IOSDeployDebuggerState.attached + : _IOSDeployDebuggerState.detached; + if (!debuggerCompleter.isCompleted) { + debuggerCompleter.complete(attachSuccess); + } + return; + } + + // (lldb) process signal SIGSTOP + // or + // process signal SIGSTOP + if (line.contains(_signalStop)) { + // The app is about to be stopped. Only show in verbose mode. + _logger.printTrace(line); + return; + } + + // error: Failed to send signal 17: failed to send signal 17 + if (line.contains(_signalStopError)) { + // The stop signal failed, force exit. + exit(); + return; + } + + if (line == _backTraceAll) { + // The app is stopped and the backtrace for all threads will be printed. + _logger.printTrace(line); + // Even though we're not "detached", just stopped, mark as detached so the backtrace + // is only show in verbose. + _debuggerState = _IOSDeployDebuggerState.detached; + + // If we paused the app and are waiting to resume it, complete the completer + final Completer? processResumeCompleter = _processResumeCompleter; + if (processResumeCompleter != null) { + _processResumeCompleter = null; + processResumeCompleter.complete(); + } + return; + } + + if (line.contains('PROCESS_STOPPED') || _lldbProcessStopped.hasMatch(line)) { + // The app has been stopped. Dump the backtrace, and detach. + _logger.printTrace(line); + _iosDeployProcess?.stdin.writeln(_backTraceAll); + if (_processResumeCompleter == null) { + detach(); + } + return; + } + + if (line.contains('PROCESS_EXITED') || _lldbProcessExit.hasMatch(line)) { + // The app exited or crashed, so exit. Continue passing debugging + // messages to the log reader until it exits to capture crash dumps. + _logger.printTrace(line); + if (line.contains(_lostConnectionPattern)) { + _lostConnection = true; + } + exit(); + return; + } + if (_lldbProcessDetached.hasMatch(line)) { + // The debugger has detached from the app, and there will be no more debugging messages. + // Kill the ios-deploy process. + _logger.printTrace(line); + exit(); + return; + } + + if (_lldbProcessResuming.hasMatch(line)) { + _logger.printTrace(line); + // we marked this detached when we received [_backTraceAll] + _debuggerState = _IOSDeployDebuggerState.attached; + return; + } + + if (_debuggerState != _IOSDeployDebuggerState.attached) { + _logger.printTrace(line); + return; + } + if (lastLineFromDebugger != null && lastLineFromDebugger!.isNotEmpty && line.isEmpty) { + // The lldb console stream from ios-deploy is separated lines by an extra \r\n. + // To avoid all lines being double spaced, if the last line from the + // debugger was not an empty line, skip this empty line. + // This will still cause "legit" logged newlines to be doubled... + } else if (!_debuggerOutput.isClosed) { + _debuggerOutput.add(line); + + // Sometimes the `ios-deploy` process does not return logs from the + // application after attaching, such as the Dart VM url. In CI, + // `idevicesyslog` is used as a fallback to get logs. Print a + // message to indicate whether logs were received from `ios-deploy` + // to help with debugging. + if (!receivedLogs) { + _logger.printTrace('Received logs from ios-deploy.'); + receivedLogs = true; + } + } + lastLineFromDebugger = line; + }); final StreamSubscription stderrSubscription = _iosDeployProcess!.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { _monitorIOSDeployFailure(line, _logger); _logger.printTrace(line); diff --git a/packages/flutter_tools/lib/src/ios/lldb.dart b/packages/flutter_tools/lib/src/ios/lldb.dart index 8da71ee17d082..35d0df37551db 100644 --- a/packages/flutter_tools/lib/src/ios/lldb.dart +++ b/packages/flutter_tools/lib/src/ios/lldb.dart @@ -10,7 +10,7 @@ import 'dart:async'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; -import '../convert.dart'; +import '../base/utils.dart'; /// LLDB is the default debugger in Xcode on macOS. Once the application has /// launched on a physical iOS device, you can attach to it using LLDB. @@ -148,8 +148,7 @@ return False ); final StreamSubscription stdoutSubscription = _lldbProcess!.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { if (_isAttached && !_ignoreLog(line)) { // Only forwards logs after LLDB is attached. All logs before then are part of the @@ -163,8 +162,7 @@ return False }); final StreamSubscription stderrSubscription = _lldbProcess!.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { _monitorError(line); if (_isAttached && !_ignoreLog(line)) { diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 200120f8dde89..d61c40d1e5005 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -918,6 +918,12 @@ _XCResultIssueHandlingResult _handleXCResultIssue({ missingModule: missingModule, ); } + } else if (message.toLowerCase().contains('has been modified since')) { + return _XCResultIssueHandlingResult( + requiresProvisioningProfile: false, + hasProvisioningProfileIssue: false, + modifiedPrecompiledSource: true, + ); } return _XCResultIssueHandlingResult( requiresProvisioningProfile: false, @@ -937,6 +943,7 @@ Future _handleIssues( var requiresProvisioningProfile = false; var hasProvisioningProfileIssue = false; var issueDetected = false; + var modifiedPrecompiledSource = false; String? missingPlatform; final duplicateModules = []; final missingModules = []; @@ -962,6 +969,7 @@ Future _handleIssues( if (handlingResult.missingModule != null) { missingModules.add(handlingResult.missingModule!); } + modifiedPrecompiledSource = handlingResult.modifiedPrecompiledSource; issueDetected = true; } } else if (xcResult != null) { @@ -1032,6 +1040,13 @@ Future _handleIssues( ); } } + } else if (modifiedPrecompiledSource) { + logger.printError( + 'โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n' + 'A precompiled file has been changed since last built. Please run "flutter clean" to clear ' + 'the cache.\n' + 'โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•', + ); } return issueDetected; } @@ -1169,6 +1184,7 @@ class _XCResultIssueHandlingResult { this.missingPlatform, this.duplicateModule, this.missingModule, + this.modifiedPrecompiledSource = false, }); /// An issue indicates that user didn't provide the provisioning profile. @@ -1186,6 +1202,10 @@ class _XCResultIssueHandlingResult { /// An issue indicates a module was imported but not found, potentially due /// to it being Swift Package Manager compatible only. final String? missingModule; + + /// An issue indicates that a source file, such as a header in the Flutter framework, has + /// changed since last built. This requires "flutter clean" to resolve. + final bool modifiedPrecompiledSource; } const _kResultBundlePath = 'temporary_xcresult_bundle'; diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index aa52d057f7228..3de57fe78fa83 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -832,40 +832,22 @@ class _IOSSimulatorLogReader extends DeviceLogReader { // Unified logging iOS 11 and greater (introduced in iOS 10). if (await device.sdkMajorVersion >= 11) { _deviceProcess = await launchDeviceUnifiedLogging(device, _appName); - _deviceProcess?.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onUnifiedLoggingLine); - _deviceProcess?.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onUnifiedLoggingLine); + _deviceProcess?.stdout.transform(utf8LineDecoder).listen(_onUnifiedLoggingLine); + _deviceProcess?.stderr.transform(utf8LineDecoder).listen(_onUnifiedLoggingLine); } else { // Fall back to syslog parsing. await device.ensureLogsExists(); _deviceProcess = await launchDeviceSystemLogTool(device); - _deviceProcess?.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onSysLogDeviceLine); - _deviceProcess?.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onSysLogDeviceLine); + _deviceProcess?.stdout.transform(utf8LineDecoder).listen(_onSysLogDeviceLine); + _deviceProcess?.stderr.transform(utf8LineDecoder).listen(_onSysLogDeviceLine); } // Track system.log crashes. // ReportCrash[37965]: Saved crash report for FlutterRunner[37941]... _systemProcess = await launchSystemLogTool(device); if (_systemProcess != null) { - _systemProcess?.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onSystemLine); - _systemProcess?.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_onSystemLine); + _systemProcess?.stdout.transform(utf8LineDecoder).listen(_onSystemLine); + _systemProcess?.stderr.transform(utf8LineDecoder).listen(_onSystemLine); } // We don't want to wait for the process or its callback. Best effort diff --git a/packages/flutter_tools/lib/src/ios/xcode_debug.dart b/packages/flutter_tools/lib/src/ios/xcode_debug.dart index d6bbc1298b73c..cc7b615a8be36 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_debug.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_debug.dart @@ -16,6 +16,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../base/template.dart'; +import '../base/utils.dart'; import '../build_info.dart'; import '../convert.dart'; import '../macos/xcode.dart'; @@ -106,36 +107,34 @@ class XcodeDebug { ]); final stdoutBuffer = StringBuffer(); - stdoutSubscription = startDebugActionProcess!.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - _logger.printTrace(line); - stdoutBuffer.write(line); - }); + stdoutSubscription = startDebugActionProcess!.stdout.transform(utf8LineDecoder).listen(( + String line, + ) { + _logger.printTrace(line); + stdoutBuffer.write(line); + }); final stderrBuffer = StringBuffer(); var permissionWarningPrinted = false; // console.log from the script are found in the stderr - stderrSubscription = startDebugActionProcess!.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - _logger.printTrace('stderr: $line'); - stderrBuffer.write(line); - - // This error may occur if Xcode automation has not been allowed. - // Example: Failed to get workspace: Error: An error occurred. - if (!permissionWarningPrinted && - line.contains('Failed to get workspace') && - line.contains('An error occurred')) { - _logger.printError( - 'There was an error finding the project in Xcode. Ensure permission ' - 'has been given to control Xcode in Settings > Privacy & Security > Automation.', - ); - permissionWarningPrinted = true; - } - }); + stderrSubscription = startDebugActionProcess!.stderr.transform(utf8LineDecoder).listen(( + String line, + ) { + _logger.printTrace('stderr: $line'); + stderrBuffer.write(line); + + // This error may occur if Xcode automation has not been allowed. + // Example: Failed to get workspace: Error: An error occurred. + if (!permissionWarningPrinted && + line.contains('Failed to get workspace') && + line.contains('An error occurred')) { + _logger.printError( + 'There was an error finding the project in Xcode. Ensure permission ' + 'has been given to control Xcode in Settings > Privacy & Security > Automation.', + ); + permissionWarningPrinted = true; + } + }); final int exitCode = await startDebugActionProcess!.exitCode.whenComplete(() async { await stdoutSubscription?.cancel(); diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart index 07a5df00f020b..4e1b82dd2558a 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart @@ -9,10 +9,16 @@ import '../../../base/file_system.dart'; import '../../../base/io.dart'; import '../../../globals.dart' as globals; -/// Flutter expects `clang++` to be on the path on Linux hosts. +/// Returns a [CCompilerConfig] matching a toolchain that would be used to compile the main app with +/// CMake on Linux. /// -/// Search for the accompanying `clang`, `ar`, and `ld`. -Future cCompilerConfigLinux() async { +/// Flutter expects `clang++` to be on the path on Linux hosts, which this uses to search for the +/// accompanying `clang`, `ar`, and `ld`. +/// +/// If [throwIfNotFound] is false, this is allowed to fail (in which case `null`) is returned. This +/// is used for `flutter test` setups, where no main app is compiled and we thus don't want a +/// `clang` toolchain to be a requirement. +Future cCompilerConfigLinux({required bool throwIfNotFound}) async { const kClangPlusPlusBinary = 'clang++'; // NOTE: these binaries sometimes have different names depending on the installation; // thus, we check for a few possible options (in order of preference). @@ -25,30 +31,53 @@ Future cCompilerConfigLinux() async { kClangPlusPlusBinary, ]); if (whichResult.exitCode != 0) { - throwToolExit('Failed to find $kClangPlusPlusBinary on PATH.'); + if (throwIfNotFound) { + throwToolExit('Failed to find $kClangPlusPlusBinary on PATH.'); + } else { + return null; + } } File clangPpFile = globals.fs.file((whichResult.stdout as String).trim()); clangPpFile = globals.fs.file(await clangPpFile.resolveSymbolicLinks()); final Directory clangDir = clangPpFile.parent; - return CCompilerConfig( - linker: _findExecutableIfExists(path: clangDir, possibleExecutableNames: kLdBinaryOptions), - compiler: _findExecutableIfExists(path: clangDir, possibleExecutableNames: kClangBinaryOptions), - archiver: _findExecutableIfExists(path: clangDir, possibleExecutableNames: kArBinaryOptions), + Uri? findExecutable({required List possibleExecutableNames, required Directory path}) { + final Uri? found = _findExecutableIfExists( + possibleExecutableNames: possibleExecutableNames, + path: path, + ); + + if (found == null && throwIfNotFound) { + throwToolExit('Failed to find any of $possibleExecutableNames in $path'); + } + + return found; + } + + final Uri? linker = findExecutable(path: clangDir, possibleExecutableNames: kLdBinaryOptions); + final Uri? compiler = findExecutable( + path: clangDir, + possibleExecutableNames: kClangBinaryOptions, ); + final Uri? archiver = findExecutable(path: clangDir, possibleExecutableNames: kArBinaryOptions); + + if (linker == null || compiler == null || archiver == null) { + assert(!throwIfNotFound); // otherwise, findExecutable would have thrown + return null; + } + return CCompilerConfig(linker: linker, compiler: compiler, archiver: archiver); } /// Searches for an executable with a name in [possibleExecutableNames] /// at [path] and returns the first one it finds, if one is found. -/// Otherwise, throws an error. -Uri _findExecutableIfExists({ +/// Otherwise, returns `null`. +Uri? _findExecutableIfExists({ required List possibleExecutableNames, required Directory path, }) { return possibleExecutableNames - .map((execName) => path.childFile(execName)) - .where((file) => file.existsSync()) - .map((file) => file.uri) - .firstOrNull ?? - throwToolExit('Failed to find any of $possibleExecutableNames in $path'); + .map((execName) => path.childFile(execName)) + .where((file) => file.existsSync()) + .map((file) => file.uri) + .firstOrNull; } diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart index 0d1d71b0d1c0b..71d4729e46411 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart @@ -10,7 +10,6 @@ import '../../../base/common.dart'; import '../../../base/file_system.dart'; import '../../../base/io.dart'; import '../../../build_info.dart'; -import '../../../convert.dart'; import '../../../globals.dart' as globals; /// Create an `Info.plist` in [target] for a framework with a single dylib. @@ -169,23 +168,37 @@ Future codesignDylib( /// Flutter expects `xcrun` to be on the path on macOS hosts. /// /// Use the `clang`, `ar`, and `ld` that would be used if run with `xcrun`. -Future cCompilerConfigMacOS() async { +/// +/// If no XCode installation was found, [throwIfNotFound] controls whether this +/// throws or returns `null`. +Future cCompilerConfigMacOS({required bool throwIfNotFound}) async { + final Uri? compiler = await _findXcrunBinary('clang', throwIfNotFound); + final Uri? archiver = await _findXcrunBinary('ar', throwIfNotFound); + final Uri? linker = await _findXcrunBinary('ld', throwIfNotFound); + + if (compiler == null || archiver == null || linker == null) { + assert(!throwIfNotFound); + return null; + } + + return CCompilerConfig(compiler: compiler, archiver: archiver, linker: linker); +} + +/// Invokes `xcrun --find` to find the full path to [binaryName]. +Future _findXcrunBinary(String binaryName, bool throwIfNotFound) async { final ProcessResult xcrunResult = await globals.processManager.run([ 'xcrun', - 'clang', - '--version', + '--find', + binaryName, ]); if (xcrunResult.exitCode != 0) { - throwToolExit('Failed to find clang with xcrun:\n${xcrunResult.stderr}'); + if (throwIfNotFound) { + throwToolExit('Failed to find $binaryName with xcrun:\n${xcrunResult.stderr}'); + } else { + return null; + } } - final String installPath = LineSplitter.split( - xcrunResult.stdout as String, - ).firstWhere((String s) => s.startsWith('InstalledDir: ')).split(' ').last; - return CCompilerConfig( - compiler: Uri.file('$installPath/clang'), - archiver: Uri.file('$installPath/ar'), - linker: Uri.file('$installPath/ld'), - ); + return Uri.file((xcrunResult.stdout as String).trim()); } /// Converts [fileName] into a suitable framework name. diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/targets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/targets.dart index b6dd0d42fd938..cc0de9f245290 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/targets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/targets.dart @@ -194,7 +194,19 @@ sealed class CodeAssetTarget extends AssetBuildTarget { late final CCompilerConfig? cCompilerConfigSync; - Future setCCompilerConfig(); + /// On platforms where the Flutter app is compiled with a native toolchain, configures this target + /// to contain a [CCompilerConfig] matching that toolchain. + /// + /// While hooks are supposed to be able to find a toolchain on their own, we want them to use the + /// same tools used to build the main app to make static linking easier in the future. So if we're + /// e.g. on Linux and use `clang` to compile the app, hooks should use the same `clang` as a + /// compiler too. + /// + /// If [mustMatchAppBuild] is true (the default), this should throw if the expected toolchain + /// could not be found. For `flutter test` setups where no app is compiled, we _prefer_ to use the + /// same toolchain but would allow not passing a [CCompilerConfig] if that fails. This allows + /// hooks that only download code assets instead of compiling them to still function. + Future setCCompilerConfig({bool mustMatchAppBuild = true}); List get codeAssetExtensions { return [ @@ -223,7 +235,9 @@ class WindowsAssetTarget extends CodeAssetTarget { ]; @override - Future setCCompilerConfig() async => cCompilerConfigSync = await cCompilerConfigWindows(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) async => + // TODO(simolus3): Respect the mustMatchAppBuild option in cCompilerConfigWindows. + cCompilerConfigSync = await cCompilerConfigWindows(); } final class LinuxAssetTarget extends CodeAssetTarget { @@ -231,7 +245,8 @@ final class LinuxAssetTarget extends CodeAssetTarget { : super(os: OS.linux); @override - Future setCCompilerConfig() async => cCompilerConfigSync = await cCompilerConfigLinux(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) async => + cCompilerConfigSync = await cCompilerConfigLinux(throwIfNotFound: mustMatchAppBuild); @override List get extensions => [ @@ -252,7 +267,8 @@ final class IOSAssetTarget extends CodeAssetTarget { final FileSystem fileSystem; @override - Future setCCompilerConfig() async => cCompilerConfigSync = await cCompilerConfigMacOS(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) async => + cCompilerConfigSync = await cCompilerConfigMacOS(throwIfNotFound: mustMatchAppBuild); IOSCodeConfig _getIOSConfig(Map environmentDefines, FileSystem fileSystem) { final String? sdkRoot = environmentDefines[kSdkRoot]; @@ -299,7 +315,8 @@ final class MacOSAssetTarget extends CodeAssetTarget { } @override - Future setCCompilerConfig() async => cCompilerConfigSync = await cCompilerConfigMacOS(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) async => + cCompilerConfigSync = await cCompilerConfigMacOS(throwIfNotFound: mustMatchAppBuild); } final class AndroidAssetTarget extends CodeAssetTarget { @@ -315,7 +332,8 @@ final class AndroidAssetTarget extends CodeAssetTarget { final AndroidCodeConfig? _androidCodeConfig; @override - Future setCCompilerConfig() async => cCompilerConfigSync = await cCompilerConfigAndroid(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) async => + cCompilerConfigSync = await cCompilerConfigAndroid(); @override List get extensions => [ @@ -362,7 +380,8 @@ final class FlutterTesterAssetTarget extends CodeAssetTarget { CCompilerConfig? get cCompilerConfigSync => subtarget.cCompilerConfigSync; @override - Future setCCompilerConfig() async => subtarget.setCCompilerConfig(); + Future setCCompilerConfig({bool mustMatchAppBuild = true}) => + subtarget.setCCompilerConfig(mustMatchAppBuild: false); } List _androidArchs(TargetPlatform targetPlatform, String? androidArchsEnvironment) { diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index 2284eba0cb8fa..e0877fb52e74a 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -88,12 +88,15 @@ const kExitMessage = 'instance in Chrome.\nThis can happen if the websocket connection used by the ' 'web tooling is unable to correctly establish a connection, for example due to a firewall.'; +const kNoClientConnectedMessage = 'Recompile complete. No client connected.'; + class ResidentWebRunner extends ResidentRunner { ResidentWebRunner( FlutterDevice device, { String? target, bool stayResident = true, bool machine = false, + String? projectRootPath, required this.flutterProject, required DebuggingOptions debuggingOptions, required FileSystem fileSystem, @@ -123,6 +126,7 @@ class ResidentWebRunner extends ResidentRunner { outputPreferences: outputPreferences, ), dartBuilder: hookRunner, + projectRootPath: projectRootPath, ); final FileSystem _fileSystem; @@ -404,6 +408,13 @@ class ResidentWebRunner extends ResidentRunner { ); } + /// Handles the no clients available scenario gracefully. + OperationResult _handleNoClientsAvailable(Status status) { + status.stop(); + _logger.printStatus(kNoClientConnectedMessage); + return OperationResult.ok; + } + @override Future restart({ bool fullRestart = false, @@ -487,9 +498,7 @@ class ResidentWebRunner extends ResidentRunner { } if (_connectionResult == null) { - status.stop(); - _logger.printStatus('Recompile complete. No client connected..'); - return OperationResult.ok; + return _handleNoClientsAvailable(status); } // Both will be null when not assigned. @@ -504,13 +513,51 @@ class ResidentWebRunner extends ResidentRunner { // it. Otherwise, default to calling "hotRestart" without a namespace. final String hotRestartMethod = _registeredMethodsForService['hotRestart'] ?? 'hotRestart'; - await _vmService.service.callMethod(hotRestartMethod); + + try { + await _vmService.service.callMethod(hotRestartMethod); + } on vmservice.RPCError catch (e) { + // DWDS throws an RPC error with kIsolateCannotReload code when there are no + // browser clients currently connected during a hot restart operation. + + // TODO(61757): Remove this temporary workaround once vm_service is fixed. + // There's a bug in vm_service where it re-encodes RPCErrors as kServerError + // instead of preserving the original error code. Until that's fixed, we need + // to check for both kIsolateCannotReload and kServerError for this method. + if (e.callingMethod == hotRestartMethod && + (e.code == vmservice.RPCErrorKind.kIsolateCannotReload.code || + e.code == vmservice.RPCErrorKind.kServerError.code)) { + return _handleNoClientsAvailable(status); + } + // Re-throw other RPC errors + rethrow; + } } else { final DateTime reloadStart = _systemClock.now(); final vmservice.VM vm = await _vmService.service.getVM(); - final vmservice.ReloadReport report = await _vmService.service.reloadSources( - vm.isolates!.first.id!, - ); + final String hotReloadMethod = + _registeredMethodsForService['reloadSources'] ?? 'reloadSources'; + + // Check if there are any isolates available + if (vm.isolates == null || vm.isolates!.isEmpty) { + _logger.printTrace('No isolates available for hot reload'); + return _handleNoClientsAvailable(status); + } + + vmservice.ReloadReport report; + try { + report = await _vmService.service.reloadSources(vm.isolates!.first.id!); + } on vmservice.RPCError catch (e) { + // DWDS throws an RPC error with kIsolateCannotReload code when there are no + // browser clients currently connected during a hot reload operation. + if (e.callingMethod == hotReloadMethod && + e.code == vmservice.RPCErrorKind.kIsolateCannotReload.code) { + return _handleNoClientsAvailable(status); + } + // Re-throw other RPC errors + rethrow; + } + reloadDuration = _systemClock.now().difference(reloadStart); final contents = ReloadReportContents.fromReloadReport(report); final bool success = contents.success ?? false; @@ -889,7 +936,7 @@ class ResidentWebRunner extends ResidentRunner { DebugConnectionInfo( wsUri: websocketUri, devToolsUri: Uri.tryParse(debugConnection.devToolsUri ?? ''), - // TODO(bkonyi): surface DTD URI once it's visible from DWDS + dtdUri: Uri.tryParse(debugConnection.dtdUri ?? ''), ), ); }), diff --git a/packages/flutter_tools/lib/src/macos/xcdevice.dart b/packages/flutter_tools/lib/src/macos/xcdevice.dart index 9534531b1eb7d..07b2de8b2ab11 100644 --- a/packages/flutter_tools/lib/src/macos/xcdevice.dart +++ b/packages/flutter_tools/lib/src/macos/xcdevice.dart @@ -14,6 +14,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/utils.dart'; import '../base/version.dart'; import '../build_info.dart'; import '../cache.dart'; @@ -279,8 +280,7 @@ class XCDevice { final Process process = await _processUtils.start(cmd); final StreamSubscription stdoutSubscription = process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { String? mappedLine = line; if (mapFunction != null) { @@ -292,8 +292,7 @@ class XCDevice { } }); final StreamSubscription stderrSubscription = process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { String? mappedLine = line; if (mapFunction != null) { diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 40eee32063cdc..4dacd644873d4 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:collection'; + import 'package:meta/meta.dart'; import 'package:xml/xml.dart'; import 'package:yaml/yaml.dart'; @@ -229,7 +231,10 @@ class FlutterProject { /// The location of the generated scaffolding project for hosting widget /// previews from this project. - Directory get widgetPreviewScaffold => dartTool.childDirectory('widget_preview_scaffold'); + // TODO(bkonyi): don't create this project in $TMP. + // See https://github.com/flutter/flutter/issues/179036 + late final Directory widgetPreviewScaffold = directory.fileSystem.systemTempDirectory + .createTempSync('widget_preview_scaffold'); /// The directory containing the generated code for this project. Directory get generated => directory.absolute @@ -238,6 +243,21 @@ class FlutterProject { .childDirectory('generated') .childDirectory(manifest.appName); + /// The set of directories created by the tool containing ephemeral state. + // TODO(bkonyi): provide getters for each project type that returns the set + // of known ephemeral files / directories. + Set get ephemeralDirectories => UnmodifiableSetView(_ephemeralDirectories); + late final _ephemeralDirectories = { + buildDirectory, + android.ephemeralDirectory, + ios.ephemeralDirectory, + ios.ephemeralModuleDirectory, + ios.symlinks, + linux.ephemeralDirectory, + macos.ephemeralDirectory, + windows.ephemeralDirectory, + }; + /// The generated Dart plugin registrant for non-web platforms. File get dartPluginRegistrant => dartTool.childDirectory('flutter_build').childFile('dart_plugin_registrant.dart'); @@ -313,6 +333,18 @@ class FlutterProject { return manifest; } + /// Reloads the content of [pubspecFile] and updates the contents of [manifest]. + void reloadManifest({required Logger logger, required FileSystem fs}) { + _manifest = _readManifest(pubspecFile.path, logger: logger, fileSystem: fs); + } + + /// Returns the MD5 hash of the contents of [manifest], ensuring [manifest] is up to date before + /// calculating the hash. + String computeManifestMD5Hash({required Logger logger, required FileSystem fs}) { + reloadManifest(logger: logger, fs: fs); + return _manifest.computeMD5Hash(); + } + /// Replaces the content of [pubspecFile] with the contents of [updated] and /// sets [manifest] to the [updated] manifest. void replacePubspec(FlutterManifest updated) { diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart index 776e680070628..cd2d4a9b4b348 100644 --- a/packages/flutter_tools/lib/src/protocol_discovery.dart +++ b/packages/flutter_tools/lib/src/protocol_discovery.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'base/io.dart'; import 'base/logger.dart'; +import 'base/utils.dart'; import 'device.dart'; import 'device_port_forwarder.dart'; import 'globals.dart' as globals; @@ -85,7 +86,7 @@ class ProtocolDiscovery { /// Port forwarding is only attempted when this is invoked, /// for each VM Service URL in the stream. Stream get uris { - final Stream uriStream = _uriStreamController.stream.transform( + final Stream uriStream = _uriStreamController.stream.transformWithCallSite( _throttle(waitDuration: throttleDuration), ); return uriStream.asyncMap(_forwardPort); diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index d4837c2d5aa31..7fb86c0cc9a88 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -1123,7 +1123,7 @@ abstract class ResidentRunner extends ResidentHandlers { processManager: globals.processManager, platform: globals.platform, analytics: globals.analytics, - projectDir: globals.fs.currentDirectory, + projectDir: globals.fs.directory(projectRootPath), packageConfigPath: debuggingOptions.buildInfo.packageConfigPath, generateDartPluginRegistry: generateDartPluginRegistry, defines: { @@ -1215,7 +1215,7 @@ abstract class ResidentRunner extends ResidentHandlers { /// /// Returns the exit code that we should use for the flutter tool process; 0 /// for success, 1 for user error (e.g. bad arguments), 2 for other failures. - Future run({ + Future run({ Completer? connectionInfoCompleter, Completer? appStartedCompleter, String? route, @@ -1225,7 +1225,7 @@ abstract class ResidentRunner extends ResidentHandlers { /// /// [needsFullRestart] defaults to `true`, and controls if the frontend server should /// compile a full dill. This should be set to `false` if this is called in [ResidentRunner.run], since that method already performs an initial compilation. - Future attach({ + Future attach({ Completer? connectionInfoCompleter, Completer? appStartedCompleter, bool needsFullRestart = true, diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index b22c97e42d0aa..8db4026b33b36 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -128,12 +128,11 @@ class HotRunner extends ResidentRunner { final benchmarkData = >{}; + @visibleForTesting + String? get targetPlatformName => _targetPlatformName; String? _targetPlatformName; - TargetPlatform get _targetPlatform => _targetPlatformName != null - ? getTargetPlatformForName(_targetPlatformName!) - : throw ArgumentError( - 'Access to the target platform needs a call to _calculateTargetPlatform first', - ); + final _targetPlatforms = {}; + String? _sdkName; bool? _emulator; @@ -150,15 +149,22 @@ class HotRunner extends ResidentRunner { if (_targetPlatformName != null) { return; } - + assert(_targetPlatforms.isEmpty); switch (flutterDevices.length) { case 1: final Device device = flutterDevices.first.device!; - _targetPlatformName = getNameForTargetPlatform(await device.targetPlatform); + final TargetPlatform targetPlatform = await device.targetPlatform; + _targetPlatformName = getNameForTargetPlatform(targetPlatform); + _targetPlatforms.add(targetPlatform); _sdkName = await device.sdkNameAndVersion; _emulator = await device.isLocalEmulator; case > 1: _targetPlatformName = 'multiple'; + _targetPlatforms.addAll( + await Future.wait([ + for (final flutterDevice in flutterDevices) flutterDevice.device!.targetPlatform, + ]), + ); _sdkName = 'multiple'; _emulator = false; default: @@ -302,7 +308,7 @@ class HotRunner extends ResidentRunner { final initialUpdateDevFSsTimer = Stopwatch()..start(); final UpdateFSReport devfsResult = await _updateDevFS( fullRestart: needsFullRestart, - targetPlatform: _targetPlatform, + targetPlatforms: _targetPlatforms, ); _addBenchmarkData( @@ -485,23 +491,26 @@ class HotRunner extends ResidentRunner { Future _updateDevFS({ bool fullRestart = false, - required TargetPlatform targetPlatform, + required Set targetPlatforms, }) async { final bool isFirstUpload = !assetBundle.wasBuiltOnce(); final bool rebuildBundle = assetBundle.needsBuild(); if (rebuildBundle) { - globals.printTrace('Updating assets'); - final int result = await assetBundle.build( - flutterHookResult: await dartBuilder?.runHooks( + for (final targetPlatform in targetPlatforms) { + globals.printTrace('Updating assets for ${targetPlatform.osName}'); + final int result = await assetBundle.build( + flutterHookResult: await dartBuilder?.runHooks( + targetPlatform: targetPlatform, + environment: environment, + logger: _logger, + ), + packageConfigPath: debuggingOptions.buildInfo.packageConfigPath, + flavor: debuggingOptions.buildInfo.flavor, targetPlatform: targetPlatform, - environment: environment, - logger: _logger, - ), - packageConfigPath: debuggingOptions.buildInfo.packageConfigPath, - flavor: debuggingOptions.buildInfo.flavor, - ); - if (result != 0) { - return UpdateFSReport(); + ); + if (result != 0) { + return UpdateFSReport(); + } } } @@ -611,7 +620,7 @@ class HotRunner extends ResidentRunner { final restartTimer = Stopwatch()..start(); UpdateFSReport updatedDevFS; try { - updatedDevFS = await _updateDevFS(fullRestart: true, targetPlatform: _targetPlatform); + updatedDevFS = await _updateDevFS(fullRestart: true, targetPlatforms: _targetPlatforms); } finally { hotRunnerConfig!.updateDevFSComplete(); } @@ -1026,7 +1035,7 @@ class HotRunner extends ResidentRunner { final devFSTimer = Stopwatch()..start(); UpdateFSReport updatedDevFS; try { - updatedDevFS = await _updateDevFS(targetPlatform: _targetPlatform); + updatedDevFS = await _updateDevFS(targetPlatforms: _targetPlatforms); } finally { hotRunnerConfig!.updateDevFSComplete(); } diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index b34419f6b0054..1c5811835d42c 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1603,7 +1603,10 @@ abstract class FlutterCommand extends Command { }); if (argParser.options.containsKey(FlutterOptions.kDartDefinesOption)) { - dartDefines.addAll(stringsArg(FlutterOptions.kDartDefinesOption)); + final Iterable defines = stringsArg( + FlutterOptions.kDartDefinesOption, + ).where((string) => string.isNotEmpty); + dartDefines.addAll(defines); } return dartDefines; diff --git a/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart new file mode 100644 index 0000000000000..a741b2683d765 --- /dev/null +++ b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart @@ -0,0 +1,65 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:yaml/yaml.dart'; +import 'package:yaml_edit/yaml_edit.dart'; + +import '../base/file_system.dart'; +import '../globals.dart' as globals; + +void updateShorebirdYaml(String? flavor, String shorebirdYamlPath, {required Map environment}) { + final File shorebirdYaml = globals.fs.file(shorebirdYamlPath); + if (!shorebirdYaml.existsSync()) { + throw Exception('shorebird.yaml not found at $shorebirdYamlPath'); + } + final YamlDocument input = loadYamlDocument(shorebirdYaml.readAsStringSync()); + final YamlMap yamlMap = input.contents as YamlMap; + final Map compiled = compileShorebirdYaml(yamlMap, flavor: flavor, environment: environment); + // Currently we write out over the same yaml file, we should fix this to + // write to a new .json file instead and avoid naming confusion between the + // input and compiled files. + final YamlEditor yamlEditor = YamlEditor(''); + yamlEditor.update([], compiled); + shorebirdYaml.writeAsStringSync(yamlEditor.toString(), flush: true); +} + +String appIdForFlavor(YamlMap yamlMap, {required String? flavor}) { + if (flavor == null || flavor.isEmpty) { + final String? defaultAppId = yamlMap['app_id'] as String?; + if (defaultAppId == null || defaultAppId.isEmpty) { + throw Exception('Cannot find "app_id" in shorebird.yaml'); + } + return defaultAppId; + } + + final YamlMap? yamlFlavors = yamlMap['flavors'] as YamlMap?; + if (yamlFlavors == null) { + throw Exception('Cannot find "flavors" in shorebird.yaml.'); + } + final String? flavorAppId = yamlFlavors[flavor] as String?; + if (flavorAppId == null || flavorAppId.isEmpty) { + throw Exception('Cannot find "app_id" for $flavor in shorebird.yaml'); + } + return flavorAppId; +} + +Map compileShorebirdYaml(YamlMap yamlMap, {required String? flavor, required Map environment}) { + final String appId = appIdForFlavor(yamlMap, flavor: flavor); + final Map compiled = { + 'app_id': appId, + }; + void copyIfSet(String key) { + if (yamlMap[key] != null) { + compiled[key] = yamlMap[key]; + } + } + copyIfSet('base_url'); + copyIfSet('auto_update'); + copyIfSet('patch_verification'); + final String? shorebirdPublicKeyEnvVar = environment['SHOREBIRD_PUBLIC_KEY']; + if (shorebirdPublicKeyEnvVar != null) { + compiled['patch_public_key'] = shorebirdPublicKeyEnvVar; + } + return compiled; +} diff --git a/packages/flutter_tools/lib/src/test/flutter_tester_device.dart b/packages/flutter_tools/lib/src/test/flutter_tester_device.dart index 815e57484a829..b3a59c7c2e43e 100644 --- a/packages/flutter_tools/lib/src/test/flutter_tester_device.dart +++ b/packages/flutter_tools/lib/src/test/flutter_tester_device.dart @@ -14,7 +14,7 @@ import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; -import '../convert.dart'; +import '../base/utils.dart'; import '../device.dart'; import '../globals.dart' as globals; import '../native_assets.dart'; @@ -297,8 +297,7 @@ class FlutterTesterTestDevice extends TestDevice { }) { for (final stream in >>[process.stderr, process.stdout]) { stream - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen( (String line) async { logger.printTrace('test $id: Shell: $line'); diff --git a/packages/flutter_tools/lib/src/test/test_golden_comparator.dart b/packages/flutter_tools/lib/src/test/test_golden_comparator.dart index a021c9b066fab..fdecea3c824b8 100644 --- a/packages/flutter_tools/lib/src/test/test_golden_comparator.dart +++ b/packages/flutter_tools/lib/src/test/test_golden_comparator.dart @@ -11,6 +11,7 @@ import 'package:process/process.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; +import '../base/utils.dart'; import '../convert.dart'; import 'test_compiler.dart'; import 'test_config.dart'; @@ -273,8 +274,7 @@ class TestGoldenComparatorProcess { // Also parse stdout as a stream of JSON objects. streamIterator = StreamIterator>( process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .where((String line) { logger.printTrace('<<< $line'); return line.isNotEmpty && line[0] == '{'; @@ -283,9 +283,7 @@ class TestGoldenComparatorProcess { .cast>(), ); - process.stderr.transform(utf8.decoder).transform(const LineSplitter()).forEach(( - String line, - ) { + process.stderr.transform(utf8LineDecoder).forEach((String line) { logger.printError('<<< $line'); }); } diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index ae26f300a5548..5dcd14400b673 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -1049,6 +1049,25 @@ class GitTagVersion { } } + // Check if running on a Shorebird release branch. + final String shorebirdFlutterReleases = git + .runSync([ + 'for-each-ref', + '--contains', + gitRef, + '--format', + '%(refname:short)', + 'refs/remotes/origin/flutter_release/*', + ], workingDirectory: workingDirectory) + .stdout + .trim(); + final String? shorebirdFlutterVersion = LineSplitter.split( + shorebirdFlutterReleases, + ).map((e) => e.replaceFirst('origin/flutter_release/', '')).toList().firstOrNull; + if (shorebirdFlutterVersion != null) { + return parse(shorebirdFlutterVersion); + } + // If we don't exist in a tag, use git to find the latest tag. return _useNewestTagAndCommitsPastFallback( git: git, diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 3fe8b23c6f5f4..df13a37c65349 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -16,7 +16,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/os.dart'; import '../base/platform.dart'; -import '../convert.dart'; +import '../base/utils.dart'; /// An environment variable used to override the location of Google Chrome. const kChromeEnvironment = 'CHROME_EXECUTABLE'; @@ -245,9 +245,13 @@ class ChromiumLauncher { // debugging purposes. // See: https://github.com/flutter/flutter/issues/153928 '--disable-search-engine-choice-screen', - '--no-sandbox', - if (headless) ...['--headless', '--disable-gpu', '--window-size=2400,1800'], + if (headless) ...[ + '--no-sandbox', + '--headless', + '--disable-gpu', + '--window-size=2400,1800', + ], ...webBrowserFlags, url, ]; @@ -303,7 +307,7 @@ class ChromiumLauncher { while (true) { final Process process = await _processManager.start(args); - process.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen((String line) { + process.stdout.transform(utf8LineDecoder).listen((String line) { _logger.printTrace('[CHROME]: $line'); }); @@ -313,8 +317,7 @@ class ChromiumLauncher { var shouldRetry = false; final errors = []; await process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .map((String line) { _logger.printTrace('[CHROME]: $line'); errors.add('[CHROME]:$line'); diff --git a/packages/flutter_tools/lib/src/widget_preview/analytics.dart b/packages/flutter_tools/lib/src/widget_preview/analytics.dart index b1bb25a6789a7..c186e18bf9fee 100644 --- a/packages/flutter_tools/lib/src/widget_preview/analytics.dart +++ b/packages/flutter_tools/lib/src/widget_preview/analytics.dart @@ -26,6 +26,9 @@ class WidgetPreviewAnalytics { /// The analytics event tracking widget preview reload times. static const kPreviewReloadTime = 'preview-reload-time'; + /// The analytics event tracking actual launches of the widget preview environment. + static const kPreviewerConnected = 'previewer-connected'; + /// Provided as the label to [kLaunchTime] events if the widget preview scaffold project was /// generated as part of the widget previewer starting up. static const kScaffoldGeneratedLabel = 'scaffold-generated'; @@ -54,6 +57,15 @@ class WidgetPreviewAnalytics { ); } + /// Send an analytics event reporting that the widget preview environment has loaded successfully. + void reportPreviewerConnected() { + analytics.send( + // TODO(bkonyi): we should add a dedicated event type in unified_analytics, but this + // works as a temporary solution. + Event.timing(workflow: kWorkflow, variableName: kPreviewerConnected, elapsedMilliseconds: 0), + ); + } + /// Starts the stopwatch tracking the reload times for updated previews. /// /// This should be invoked when a file system event is detected in the preview detector. diff --git a/packages/flutter_tools/lib/src/widget_preview/dependency_graph.dart b/packages/flutter_tools/lib/src/widget_preview/dependency_graph.dart index 69d8950e66451..4e11f470d5a09 100644 --- a/packages/flutter_tools/lib/src/widget_preview/dependency_graph.dart +++ b/packages/flutter_tools/lib/src/widget_preview/dependency_graph.dart @@ -215,11 +215,14 @@ final class LibraryPreviewNode { Future populateErrors({required AnalysisContext context}) async { errors.clear(); for (final String file in files) { - errors.addAll( - ((await context.currentSession.getErrors(file)) as ErrorsResult).diagnostics - .where((error) => error.severity == Severity.error) - .toList(), - ); + final SomeErrorsResult errorsResult = await context.currentSession.getErrors(file); + // If errorsResult isn't an ErrorsResult, the analysis context has likely been disposed and + // we're in the process of shutting down. Ignore those results. + if (errorsResult is ErrorsResult) { + errors.addAll( + errorsResult.diagnostics.where((error) => error.severity == Severity.error).toList(), + ); + } } } diff --git a/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart index 64222a5048fd9..76f2d1bf44f68 100644 --- a/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart +++ b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart @@ -17,9 +17,11 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/utils.dart'; import '../convert.dart'; import '../dart/package_map.dart'; import '../project.dart'; +import 'analytics.dart'; import 'persistent_preferences.dart'; typedef DtdService = (String, DTDServiceCallback); @@ -27,6 +29,7 @@ typedef DtdService = (String, DTDServiceCallback); /// Provides services, streams, and RPC invocations to interact with the Widget Preview Scaffold. class WidgetPreviewDtdServices { WidgetPreviewDtdServices({ + required this.previewAnalytics, required this.fs, required this.logger, required this.shutdownHooks, @@ -52,6 +55,9 @@ class WidgetPreviewDtdServices { static const kSetPreference = 'setPreference'; static const kGetPreference = 'getPreference'; + static const kWidgetPreviewScaffoldStream = 'WidgetPreviewScaffold'; + static const kWidgetPreviewConnectedEvent = 'Connected'; + /// Error code for RpcException thrown when attempting to load a key from /// persistent preferences that doesn't have an entry. static const kNoValueForKey = 200; @@ -70,6 +76,7 @@ class WidgetPreviewDtdServices { @visibleForTesting late final preferences = PersistentPreferences(fs: fs); + final WidgetPreviewAnalytics previewAnalytics; final FileSystem fs; final Logger logger; final ShutdownHooks shutdownHooks; @@ -109,7 +116,16 @@ class WidgetPreviewDtdServices { Future _registerServices() async { final DartToolingDaemon dtd = _dtd!; + dtd.onEvent(kWidgetPreviewScaffoldStream).listen((DTDEvent event) { + if (event case DTDEvent( + stream: kWidgetPreviewScaffoldStream, + kind: kWidgetPreviewConnectedEvent, + )) { + previewAnalytics.reportPreviewerConnected(); + } + }); await Future.wait(>[ + dtd.streamListen(kWidgetPreviewScaffoldStream), for (final (String method, DTDServiceCallback callback) in services) dtd .registerService(kWidgetPreviewService, method, callback) @@ -175,7 +191,7 @@ class DtdLauncher { // Wait for the DTD connection information. final dtdUri = Completer(); late final StreamSubscription sub; - sub = _dtdProcess!.stdout.transform(const Utf8Decoder()).listen((String data) async { + sub = _dtdProcess!.stdout.transformWithCallSite(utf8.decoder).listen((String data) async { await sub.cancel(); final jsonData = json.decode(data) as Map; if (jsonData case {'tooling_daemon_details': {'uri': final String dtdUriString}}) { diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart b/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart index 104306a7744d7..84b2b1d6c3025 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart @@ -52,6 +52,35 @@ class PreviewCodeGenerator { static String getGeneratedPreviewFilePath(FileSystem fs) => fs.path.join('lib', 'src', 'generated_preview.dart'); + static String getGeneratedDtdConnectionInfoFilePath(FileSystem fs) => + fs.path.join('lib', 'src', 'dtd', 'dtd_connection_info.dart'); + + void populateDtdConnectionInfo(Uri dtdUri) { + final emitter = cb.DartEmitter.scoped(useNullSafetySyntax: true); + final lib = cb.Library( + (cb.LibraryBuilder b) => b + ..ignoreForFile.add('implementation_imports') + ..body.addAll([ + cb.Field((b) { + b + ..name = 'kWidgetPreviewDtdUri' + ..modifier = cb.FieldModifier.constant + ..type = cb.refer('String') + ..assignment = cb.literalString(dtdUri.toString()).code; + }), + ]), + ); + final File generatedDtdConnectionInfoFile = fs.file( + widgetPreviewScaffoldProject.directory.uri.resolve(getGeneratedDtdConnectionInfoFilePath(fs)), + ); + generatedDtdConnectionInfoFile.writeAsStringSync( + // Format the generated file for readability, particularly during feature development. + // Note: we don't really care _how_ this is formatted, just that it's formatted, so we don't + // specify a language version. + DartFormatter(languageVersion: Version.none).format(lib.accept(emitter).toString()), + ); + } + // TODO(bkonyi): update generated example now that we're computing constants /// Generates code used by the widget preview scaffold based on the preview instances listed in /// [previews]. diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart index 65ae5b186bc35..42c4be73f5d7c 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart @@ -16,6 +16,7 @@ import '../base/file_system.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/utils.dart'; +import '../project.dart'; import 'analytics.dart'; import 'dependency_graph.dart'; import 'utils.dart'; @@ -30,16 +31,17 @@ class PreviewDetector { PreviewDetector({ required this.platform, required this.previewAnalytics, - required this.projectRoot, + required this.project, required this.fs, required this.logger, required this.onChangeDetected, required this.onPubspecChangeDetected, @visibleForTesting this.watcherBuilder = _defaultWatcherBuilder, - }); + }) : projectRoot = project.directory; final Platform platform; final WidgetPreviewAnalytics previewAnalytics; + final FlutterProject project; final Directory projectRoot; final FileSystem fs; final Logger logger; @@ -53,7 +55,8 @@ class PreviewDetector { static const kWindowsFileWatcherRestartedMessage = 'WindowsDirectoryWatcher has closed and been restarted.'; StreamSubscription? _fileWatcher; - final _mutex = PreviewDetectorMutex(); + @visibleForTesting + final mutex = PreviewDetectorMutex(); var _disposed = false; @@ -68,34 +71,41 @@ class PreviewDetector { /// Starts listening for changes to Dart sources under [projectRoot] and returns /// the initial [PreviewDependencyGraph] for the project. - Future initialize() async { - // Find the initial set of previews. - await _findPreviewFunctions(projectRoot); - - // Determine which files have transitive dependencies with compile time errors. - _propagateErrors(); - - final Watcher watcher = watcherBuilder(projectRoot.path); - _fileWatcher = watcher.events.listen( - _onFileSystemEvent, - onError: (Object e, StackTrace st) { - if (platform.isWindows && - e is FileSystemException && - e.message.startsWith(kDirectoryWatcherClosedUnexpectedlyPrefix)) { - // The Windows directory watcher sometimes decides to shutdown on its own. It's - // automatically restarted by package:watcher, but we need to handle this exception. - // See https://github.com/dart-lang/tools/issues/1713 for details. - logger.printTrace(kWindowsFileWatcherRestartedMessage); - return; - } - Error.throwWithStackTrace(e, st); - }, - ); + Future initialize() { + return mutex.runGuarded(() async { + // Find the initial set of previews. + await findPreviewFunctions(projectRoot); + + // Determine which files have transitive dependencies with compile time errors. + _propagateErrors(); + + final Watcher watcher = watcherBuilder(projectRoot.path); + _fileWatcher = watcher.events.listen( + _onFileSystemEvent, + onError: (Object e, StackTrace st) { + if (platform.isWindows && + e is FileSystemException && + e.message.startsWith(kDirectoryWatcherClosedUnexpectedlyPrefix)) { + // The Windows directory watcher sometimes decides to shutdown on its own. It's + // automatically restarted by package:watcher, but we need to handle this exception. + // See https://github.com/dart-lang/tools/issues/1713 for details. + logger.printTrace(kWindowsFileWatcherRestartedMessage); + return; + } + Error.throwWithStackTrace(e, st); + }, + ); - // Wait for file watcher to finish initializing, otherwise we might miss changes and cause - // tests to flake. - await watcher.ready; - return _dependencyGraph; + // Wait for file watcher to finish initializing, otherwise we might miss changes and cause + // tests to flake. + await watcher.ready; + + // Ensure the project's manifest is up to date, just in case an update was made before the + // file watcher finished initializing. + project.reloadManifest(logger: logger, fs: fs); + + return _dependencyGraph; + }); } Future dispose() async { @@ -105,7 +115,7 @@ class PreviewDetector { _disposed = true; // Guard disposal behind a mutex to make sure the analyzer has finished // processing the latest file updates to avoid throwing an exception. - await _mutex.runGuarded(() async { + await mutex.runGuarded(() async { await _fileWatcher?.cancel(); _fileWatcher = null; await collection.dispose(); @@ -115,17 +125,32 @@ class PreviewDetector { Future _onFileSystemEvent(WatchEvent event) async { // Only process one FileSystemEntity at a time so we don't invalidate an AnalysisSession that's // in use when we call context.changeFile(...). - await _mutex.runGuarded(() async { + await mutex.runGuarded(() async { final String eventPath = event.path; + // Ignore any files under .dart_tool or ephemeral directories created by + // the tool (e.g., build/, plugin directories, etc.). + if (eventPath.doesContainDartTool || + project.ephemeralDirectories.any((dir) => eventPath.contains(dir.path))) { + return; + } // If the pubspec has changed, new dependencies or assets could have been added, requiring // the preview scaffold's pubspec to be updated. - if (eventPath.isPubspec && !eventPath.doesContainDartTool) { + if (eventPath.isPubspec) { onPubspecChangeDetected(eventPath); return; } // Only trigger a reload when changes to Dart sources are detected. We // ignore the generated preview file to avoid getting stuck in a loop. - if (!eventPath.isDartFile || eventPath.doesContainDartTool) { + if (!eventPath.isDartFile) { + return; + } + + AnalysisContext context; + try { + context = collection.contextFor(eventPath); + } on StateError { + // The modified file isn't part of the analysis context and is safe to + // ignore. return; } @@ -143,10 +168,15 @@ class PreviewDetector { // extension which may be worth using here. // We need to notify the analyzer that this file has changed so it can reanalyze the file. - final AnalysisContext context = collection.contextFor(eventPath); final File file = fs.file(eventPath); context.changeFile(file.path); - final List potentiallyAffectedFiles = await context.applyPendingFileChanges(); + final List potentiallyAffectedFiles; + try { + potentiallyAffectedFiles = await context.applyPendingFileChanges(); + } on DisposedAnalysisContextResult { + // We're shutting down. + return; + } logger.printStatus('Detected change in $eventPath.'); if (event.type == ChangeType.REMOVE) { @@ -156,7 +186,7 @@ class PreviewDetector { } for (final filePath in potentiallyAffectedFiles) { - await _fileAddedOrUpdated(context: context, filePath: filePath); + await _fileAddedOrUpdated(filePath: filePath); } // TODO(bkonyi): If _fileAddedOrUpdated is called after _fileRemoved, it'll add the removed file back... @@ -173,11 +203,8 @@ class PreviewDetector { }); } - Future _fileAddedOrUpdated({ - required AnalysisContext context, - required String filePath, - }) async { - final PreviewDependencyGraph filePreviewsMapping = await _findPreviewFunctions( + Future _fileAddedOrUpdated({required String filePath}) async { + final PreviewDependencyGraph filePreviewsMapping = await findPreviewFunctions( fs.file(filePath), ); if (filePreviewsMapping.length > 1) { @@ -210,7 +237,9 @@ class PreviewDetector { } /// Search for functions annotated with `@Preview` in the current project. - Future _findPreviewFunctions(FileSystemEntity entity) async { + @visibleForTesting + Future findPreviewFunctions(FileSystemEntity entity) async { + assert(mutex.isLocked); final PreviewDependencyGraph updatedPreviews = PreviewDependencyGraph(); logger.printStatus('Finding previews in ${entity.path}...'); @@ -225,34 +254,43 @@ class PreviewDetector { // If filePath points to a file that's part of a library, retrieve its compilation unit first // in order to get the actual path to the library. if (lib is NotLibraryButPartResult) { - final unit = - (await context.currentSession.getResolvedUnit(filePath)) as ResolvedUnitResult; + final SomeResolvedUnitResult unit = await context.currentSession.getResolvedUnit( + filePath, + ); + // Check that unit is a valid response. Otherwise, the analysis context has likely been + // disposed or we're shutting down. + if (unit is! ResolvedUnitResult) { + continue; + } lib = await context.currentSession.getResolvedLibrary( unit.libraryElement.firstFragment.source.fullName, ); } - if (lib is ResolvedLibraryResult) { - final ResolvedLibraryResult resolvedLib = lib; - final PreviewPath previewPath = lib.element.toPreviewPath(); - // This library has already been processed. - if (updatedPreviews.containsKey(previewPath)) { - continue; - } + // Check that lib is a valid response. Otherwise, the analysis context has likely been + // disposed or we're shutting down. + if (lib is! ResolvedLibraryResult) { + continue; + } + final ResolvedLibraryResult resolvedLib = lib; + final PreviewPath previewPath = lib.element.toPreviewPath(); + // This library has already been processed. + if (updatedPreviews.containsKey(previewPath)) { + continue; + } - final LibraryPreviewNode previewsForLibrary = _dependencyGraph.putIfAbsent( - previewPath, - () => LibraryPreviewNode(library: resolvedLib.element, logger: logger), - ); + final LibraryPreviewNode previewsForLibrary = _dependencyGraph.putIfAbsent( + previewPath, + () => LibraryPreviewNode(library: resolvedLib.element, logger: logger), + ); - previewsForLibrary.updateDependencyGraph(graph: _dependencyGraph, units: lib.units); - updatedPreviews[previewPath] = previewsForLibrary; + previewsForLibrary.updateDependencyGraph(graph: _dependencyGraph, units: lib.units); + updatedPreviews[previewPath] = previewsForLibrary; - // Check for errors in the library. - await previewsForLibrary.populateErrors(context: context); + // Check for errors in the library. + await previewsForLibrary.populateErrors(context: context); - // Iterate over each library's AST to find previews. - previewsForLibrary.findPreviews(lib: lib); - } + // Iterate over each library's AST to find previews. + previewsForLibrary.findPreviews(lib: lib); } } final int previewCount = updatedPreviews.values.fold( @@ -269,6 +307,7 @@ class PreviewDetector { /// as checking for newly introduced errors in files which had a transitive dependency on the /// removed file. Future _fileRemoved({required AnalysisContext context, required String filePath}) async { + assert(mutex.isLocked); final File file = fs.file(filePath); final LibraryPreviewNode? node = _dependencyGraph.values.firstWhereOrNull( (LibraryPreviewNode e) => e.files.contains(file.path), diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_manifest.dart b/packages/flutter_tools/lib/src/widget_preview/preview_manifest.dart index 755eaa3efe9b3..fb2015317ede1 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_manifest.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_manifest.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:collection/equality.dart'; +import 'package:collection/collection.dart'; import 'package:meta/meta.dart'; import '../base/file_system.dart'; @@ -48,12 +48,12 @@ class PreviewManifest { void generate() { logger.printStatus('Creating the Widget Preview Scaffold manifest at ${_manifest.path}'); assert(!_manifest.existsSync()); - _manifest.createSync(recursive: true); final manifestContents = { kManifestVersion: previewManifestVersion.toString(), kSdkVersion: cache.dartSdkVersion, kPubspecHashes: _calculatePubspecHashes(), }; + _manifest.createSync(recursive: true); _updateManifest(manifestContents); } @@ -61,30 +61,67 @@ class PreviewManifest { _manifest.writeAsStringSync(json.encode(contents)); } - Map _calculatePubspecHashes({String? updatedPubspecPath}) { - if (updatedPubspecPath != null) { - final PreviewManifestContents? manifest = _tryLoadManifest(); - if (manifest != null) { - final FlutterProject project = - [rootProject, ...rootProject.workspaceProjects].firstWhere( - (FlutterProject project) => project.pubspecFile.absolute.path == updatedPubspecPath, - ); - final Map pubspecHashes = - (manifest[kPubspecHashes]! as Map).cast(); - pubspecHashes[updatedPubspecPath] = project.manifest.computeMD5Hash(); - return pubspecHashes; - } - } + bool _isPubspecPathForProject({required FlutterProject project, required String path}) { + return project.pubspecFile.absolute.path == path; + } + Map _buildPubspecHashesMap() { return { for (final FlutterProject project in [ rootProject, - ...rootProject.workspaceProjects, + ...rootProject.workspaceProjects.where((e) => e.pubspecFile.existsSync()), ]) - project.pubspecFile.absolute.path: project.manifest.computeMD5Hash(), + project.pubspecFile.absolute.path: project.computeManifestMD5Hash(logger: logger, fs: fs), }; } + Map _calculatePubspecHashes({String? updatedPubspecPath}) { + // Keep track of the set of previous workspace projects to see if there have been any changes + // since the last time we checked. + final List previousWorkspaceProjects = rootProject.workspaceProjects; + + // Ensure the root project's manifest is up to date. + rootProject.reloadManifest(logger: logger, fs: fs); + final PreviewManifestContents? manifest = _tryLoadManifest(); + + if (updatedPubspecPath == null || manifest == null) { + return _buildPubspecHashesMap(); + } + + // If the workspace's pubspec has changed and the set of workspace projects has been + // modified since the last time we calculated hashes, recalculate all the hashes for + // simplicity. + if (_isPubspecPathForProject(project: rootProject, path: updatedPubspecPath)) { + final bool workspaceProjectUpdates = !const SetEquality().equals( + previousWorkspaceProjects.map((p) => p.directory).toSet(), + rootProject.workspaceProjects.map((p) => p.directory).toSet(), + ); + if (workspaceProjectUpdates) { + return _buildPubspecHashesMap(); + } + } + + final FlutterProject? project = [rootProject, ...rootProject.workspaceProjects] + .firstWhereOrNull( + (FlutterProject project) => + _isPubspecPathForProject(project: project, path: updatedPubspecPath), + ); + final Map pubspecHashes = (manifest[kPubspecHashes]! as Map) + .cast(); + // If the project isn't found, the pubspec is not actually part of the workspace and can be + // ignored. + if (project != null) { + if (fs.file(updatedPubspecPath).existsSync()) { + // Update the hash for the pubspec, as long as it exists. + pubspecHashes[updatedPubspecPath] = project.computeManifestMD5Hash(logger: logger, fs: fs); + } else { + // The pubspec has been deleted, so it shouldn't continue to be tracked. + pubspecHashes.remove(updatedPubspecPath); + } + } + return pubspecHashes; + } + bool shouldGenerateProject() { if (!widgetPreviewScaffold.existsSync()) { return true; @@ -142,11 +179,21 @@ class PreviewManifest { } void updatePubspecHash({String? updatedPubspecPath}) { - final PreviewManifestContents manifest = _tryLoadManifest()!; + final PreviewManifestContents? manifest = _tryLoadManifest(); + if (manifest == null) { + generate(); + return; + } manifest[kPubspecHashes] = _calculatePubspecHashes(updatedPubspecPath: updatedPubspecPath); _updateManifest(manifest); } + @visibleForTesting + Map get pubspecHashes { + final PreviewManifestContents manifest = _tryLoadManifest()!; + return (manifest[kPubspecHashes]! as Map).cast(); + } + @visibleForTesting PreviewManifest copyWith({Cache? cache}) { return PreviewManifest( diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_pubspec_builder.dart b/packages/flutter_tools/lib/src/widget_preview/preview_pubspec_builder.dart index 082f875f3c5a0..31c353bfcf39d 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_pubspec_builder.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_pubspec_builder.dart @@ -5,6 +5,7 @@ import 'package:meta/meta.dart'; import '../base/deferred_component.dart'; +import '../base/file_system.dart'; import '../base/logger.dart'; import '../convert.dart'; import '../dart/pub.dart'; @@ -57,10 +58,10 @@ class PreviewPubspecBuilder { 'web', ]; - /// Maps asset URIs to relative paths for the widget preview project to + /// Maps asset URIs to absolute paths for the widget preview project to /// include. @visibleForTesting - static Uri transformAssetUri(Uri uri) { + Uri transformAssetUri(Uri uri) { // Assets provided by packages always start with 'packages' and do not // require their URIs to be updated. if (uri.path.startsWith('packages')) { @@ -68,11 +69,13 @@ class PreviewPubspecBuilder { } // Otherwise, the asset is contained within the root project and needs // to be referenced from the widget preview scaffold project's pubspec. - return Uri(path: '../../${uri.path}'); + final Directory rootProjectDir = rootProject.directory; + final FileSystem fs = rootProjectDir.fileSystem; + return Uri(path: fs.path.join(rootProjectDir.absolute.path, uri.path)); } @visibleForTesting - static AssetsEntry transformAssetsEntry(AssetsEntry asset) { + AssetsEntry transformAssetsEntry(AssetsEntry asset) { return AssetsEntry( uri: transformAssetUri(asset.uri), flavors: asset.flavors, @@ -81,7 +84,7 @@ class PreviewPubspecBuilder { } @visibleForTesting - static DeferredComponent transformDeferredComponent(DeferredComponent component) { + DeferredComponent transformDeferredComponent(DeferredComponent component) { return DeferredComponent( name: component.name, // TODO(bkonyi): verify these library paths are always package: paths from the parent project. @@ -90,6 +93,8 @@ class PreviewPubspecBuilder { ); } + PubOutputMode get _outputMode => verbose ? PubOutputMode.all : PubOutputMode.failuresOnly; + Future populatePreviewPubspec({ required FlutterProject rootProject, String? updatedPubspecPath, @@ -118,14 +123,12 @@ class PreviewPubspecBuilder { if (project.manifest.appName.isNotEmpty) // Use `json.encode` to handle escapes correctly. project.manifest.appName: json.encode({ - // `pub add` interprets relative paths relative to the current directory. - 'path': widgetPreviewScaffoldProject.directory.fileSystem.path.relative( + 'path': widgetPreviewScaffoldProject.directory.fileSystem.path.absolute( project.directory.path, ), }), }; - final PubOutputMode outputMode = verbose ? PubOutputMode.all : PubOutputMode.failuresOnly; await pub.interactively( [ pubAdd, @@ -145,7 +148,7 @@ class PreviewPubspecBuilder { context: PubContext.pubAdd, command: pubAdd, touchesPackageConfig: true, - outputMode: outputMode, + outputMode: _outputMode, ); // Adds dependencies required by the widget preview scaffolding. @@ -160,18 +163,22 @@ class PreviewPubspecBuilder { context: PubContext.pubAdd, command: pubAdd, touchesPackageConfig: true, - outputMode: outputMode, + outputMode: _outputMode, ); + await generatePackageConfig(widgetPreviewScaffoldProject: widgetPreviewScaffoldProject); + previewManifest.updatePubspecHash(updatedPubspecPath: updatedPubspecPath); + } + + /// Generates `widget_preview_scaffold/.dart_tool/package_config.json`. + Future generatePackageConfig({required FlutterProject widgetPreviewScaffoldProject}) async { // Generate package_config.json. await pub.get( context: PubContext.create, project: widgetPreviewScaffoldProject, offline: offline, - outputMode: outputMode, + outputMode: _outputMode, ); - - previewManifest.updatePubspecHash(updatedPubspecPath: updatedPubspecPath); } void onPubspecChangeDetected(String path) { diff --git a/packages/flutter_tools/lib/src/widget_preview/utils.dart b/packages/flutter_tools/lib/src/widget_preview/utils.dart index 6b37a8904ca0a..60fe3398b4795 100644 --- a/packages/flutter_tools/lib/src/widget_preview/utils.dart +++ b/packages/flutter_tools/lib/src/widget_preview/utils.dart @@ -125,6 +125,12 @@ class PreviewDetectorMutex { _locked = false; } + /// Returns true if the lock is currently held. + /// + /// WARNING: this should only be used for assertions in functions that expect + /// the mutex to already be held. + bool get isLocked => _locked; + var _locked = false; final _outstandingRequests = Queue>(); } diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 44d8992e29e37..61a53a904979e 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -21,6 +21,7 @@ import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; import '../migrations/cmake_native_assets_migration.dart'; +import '../shorebird/shorebird_yaml.dart'; import 'migrations/build_architecture_migration.dart'; import 'migrations/show_window_migration.dart'; import 'migrations/version_migration.dart'; diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index 415edc453fa18..153da848802e6 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -182,6 +182,7 @@ class VisualStudio { String? get cmakeGenerator { // From https://cmake.org/cmake/help/v3.22/manual/cmake-generators.7.html#visual-studio-generators return switch (_majorVersion) { + 18 => 'Visual Studio 18 2026', 17 => 'Visual Studio 17 2022', _ => 'Visual Studio 16 2019', }; diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 2135c4f31d010..b6a43f824dd49 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: archive: 3.6.1 args: 2.7.0 dds: 5.0.3 - dwds: 25.1.0 + dwds: 25.1.0+2 code_builder: 4.11.0 collection: 1.19.1 completion: 1.0.2 @@ -127,4 +127,4 @@ dev_dependencies: dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: ho7nke +# PUBSPEC CHECKSUM: s8p858 diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index d975f14561d97..b633097df0133 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -346,6 +346,7 @@ "templates/widget_preview_scaffold/lib/src/widget_preview_scaffold_controller.dart.tmpl", "templates/widget_preview_scaffold/lib/src/controls.dart.tmpl", "templates/widget_preview_scaffold/lib/src/dtd/utils.dart.tmpl", + "templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl", "templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl", "templates/widget_preview_scaffold/lib/src/dtd/editor_service.dart.tmpl", "templates/widget_preview_scaffold/lib/src/generated_preview.dart.tmpl", diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl new file mode 100644 index 0000000000000..092d71d51a484 --- /dev/null +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl @@ -0,0 +1,5 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const String kWidgetPreviewDtdUri = ''; diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl index ed5352dbd4181..d978222b03e70 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl @@ -6,14 +6,12 @@ import 'dart:async'; import 'package:dtd/dtd.dart'; import 'package:json_rpc_2/json_rpc_2.dart'; +import 'package:widget_preview_scaffold/src/dtd/dtd_connection_info.dart'; +import 'package:widget_preview_scaffold/src/dtd/editor_service.dart'; import 'package:widget_preview_scaffold/src/dtd/utils.dart'; -import 'editor_service.dart'; /// Provides services, streams, and RPC invocations to interact with Flutter developer tooling. class WidgetPreviewScaffoldDtdServices with DtdEditorService { - /// Environment variable for the DTD URI. - static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI'; - // WARNING: Keep these constants and services in sync with those defined in the widget preview // scaffold's dtd_services.dart. // @@ -37,9 +35,7 @@ class WidgetPreviewScaffoldDtdServices with DtdEditorService { /// If the connection is successful, the Widget Preview Scaffold will register services and /// subscribe to various streams to interact directly with other tooling (e.g., IDEs). Future connect({Uri? dtdUri}) async { - final Uri dtdWsUri = - dtdUri ?? - Uri.parse(const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar)); + final Uri dtdWsUri = dtdUri ?? Uri.parse(kWidgetPreviewDtdUri); dtd = await DartToolingDaemon.connect(dtdWsUri); unawaited( dtd.postEvent( diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl index 2c560d2892db3..c3e01b0812c67 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl @@ -14,16 +14,16 @@ import 'package:flutter/widget_previews.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'dtd/editor_service.dart'; -import 'theme/ide_theme.dart'; -import 'theme/theme.dart'; - -import 'controls.dart'; -import 'generated_preview.dart'; -import 'utils.dart'; -import 'widget_preview.dart'; -import 'widget_preview_inspector_service.dart'; -import 'widget_preview_scaffold_controller.dart'; +import 'package:widget_preview_scaffold/src/dtd/editor_service.dart'; +import 'package:widget_preview_scaffold/src/theme/ide_theme.dart'; +import 'package:widget_preview_scaffold/src/theme/theme.dart'; + +import 'package:widget_preview_scaffold/src/controls.dart'; +import 'package:widget_preview_scaffold/src/generated_preview.dart'; +import 'package:widget_preview_scaffold/src/utils.dart'; +import 'package:widget_preview_scaffold/src/widget_preview.dart'; +import 'package:widget_preview_scaffold/src/widget_preview_inspector_service.dart'; +import 'package:widget_preview_scaffold/src/widget_preview_scaffold_controller.dart'; /// Displayed when an unhandled exception is thrown when initializing the widget /// tree for a preview (i.e., before the build phase). diff --git a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart index 991c25f090ed8..de793856b48ab 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -85,6 +85,35 @@ void main() { }, ); + testUsingContext( + 'flutter assemble can parse empty defines', + () async { + final CommandRunner commandRunner = createTestCommandRunner( + AssembleCommand( + buildSystem: TestBuildSystem.all(BuildResult(success: true), ( + Target target, + Environment environment, + ) { + expect(environment.defines, const {'DeferredComponents': 'false'}); + }), + ), + ); + await commandRunner.run([ + 'assemble', + '-o Output', + '--DartDefines=', + 'debug_macos_bundle_flutter_assets', + ]); + + expect(testLogger.traceText, contains('build succeeded.')); + }, + overrides: { + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }, + ); + testUsingContext( 'flutter assemble can parse inputs', () async { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 1f03ef1b4641d..3c6f8b05761dc 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -1495,6 +1495,57 @@ void main() { }, ); + testUsingContext( + 'does not try to attach to a new target when the original application disappears', + () async { + // Regression test for https://github.com/flutter/flutter/issues/156692. + final device = FakeAndroidDevice(id: '1') + ..portForwarder = const NoOpDevicePortForwarder() + ..onGetLogReader = () => NoOpDeviceLogReader('test'); + final hotRunner = FakeHotRunner(); + final hotRunnerFactory = FakeHotRunnerFactory()..hotRunner = hotRunner; + var attachCount = 0; + hotRunner.onAttach = + ( + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, + bool enableDevTools, + ) async { + // Mimic listening to the `vmServiceUris` stream for the FlutterDevice we're + // trying to attach to. Without the fix for + // https://github.com/flutter/flutter/issues/156692, calling `HotRunner.attach` + // multiple times would result in this stream being listened to again, causing a + // `StateError` to be thrown. + await hotRunner.flutterDevices.first.vmServiceUris!.toList(); + attachCount++; + return 0; + }; + + testDeviceManager.devices = [device]; + testFileSystem.file('lib/main.dart').createSync(); + + final command = AttachCommand( + hotRunnerFactory: hotRunnerFactory, + stdio: stdio, + logger: logger, + terminal: terminal, + signals: signals, + platform: platform, + processInfo: processInfo, + fileSystem: testFileSystem, + ); + await createTestCommandRunner(command).run(['attach', '--verbose']); + + // Ensure `HotRunner.attach` was only called once. + expect(attachCount, 1); + }, + overrides: { + FileSystem: () => testFileSystem, + ProcessManager: () => FakeProcessManager.any(), + DeviceManager: () => testDeviceManager, + }, + ); + group('prints warning when too slow', () { late SlowWarningCallbackBufferLogger logger; @@ -1546,6 +1597,9 @@ void main() { class FakeHotRunner extends Fake implements HotRunner { late Future Function(Completer?, Completer?, bool) onAttach; + @override + var flutterDevices = []; + @override var exited = false; @@ -1604,6 +1658,9 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory { this.devices = devices; this.dillOutputPath = dillOutputPath; this.projectRootPath = projectRootPath; + hotRunner.flutterDevices + ..clear() + ..addAll(devices); return hotRunner; } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart index 3d3d02df5b329..23cfc64d58beb 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart @@ -51,6 +51,14 @@ final macosPlatformCustomEnv = FakePlatform( environment: {'FLUTTER_ROOT': '/', 'HOME': '/'}, ); +final Platform macosPlatformWithShorebirdPublicKey = FakePlatform( + operatingSystem: 'macos', + environment: { + 'FLUTTER_ROOT': '/', + 'HOME': '/', + 'SHOREBIRD_PUBLIC_KEY': 'my_public_key', + } +); final Platform notMacosPlatform = FakePlatform(environment: {'FLUTTER_ROOT': '/'}); void main() { @@ -1010,4 +1018,37 @@ STDERR STUFF OperatingSystemUtils: () => FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_x64), }, ); + + testUsingContext('macOS build outputs path and size when successful', + () async { + final BuildCommand command = BuildCommand( + artifacts: artifacts, + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + processUtils: processUtils, + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + createMinimalMockProjectFiles(); + final File shorebirdYamlFile = fileSystem.file( + 'build/macos/Build/Products/Release/example.app/Contents/Frameworks/App.framework/Resources/flutter_assets/shorebird.yaml', + ) + ..createSync(recursive: true) + ..writeAsStringSync('app_id: my-app-id'); + + await createTestCommandRunner(command) + .run(const ['build', 'macos', '--no-pub']); + + final String updatedYaml = shorebirdYamlFile.readAsStringSync(); + expect(updatedYaml, contains('app_id: my-app-id')); + expect(updatedYaml, contains('patch_public_key: my_public_key')); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list([ + setUpFakeXcodeBuildHandler('Release'), + ]), + Platform: () => macosPlatformWithShorebirdPublicKey, + FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), + }); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 11c574670713a..25da553b819e3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -38,6 +38,13 @@ final Platform windowsPlatform = FakePlatform( 'USERPROFILE': '/', }, ); +final Platform windowsPlatformWithPublicKey = + FakePlatform(operatingSystem: 'windows', environment: { + 'PROGRAMFILES(X86)': r'C:\Program Files (x86)\', + 'FLUTTER_ROOT': flutterRoot, + 'USERPROFILE': '/', + 'SHOREBIRD_PUBLIC_KEY': 'my_public_key', +}); final Platform notWindowsPlatform = FakePlatform( environment: {'FLUTTER_ROOT': flutterRoot}, ); @@ -115,7 +122,9 @@ void main() { ...['--target', 'INSTALL'], if (verbose) '--verbose', ], - environment: {if (verbose) 'VERBOSE_SCRIPT_LOGGING': 'true'}, + environment: { + if (verbose) 'VERBOSE_SCRIPT_LOGGING': 'true' + }, onRun: onRun, stdout: stdout, ); @@ -131,7 +140,8 @@ void main() { setUpMockProjectFilesForBuild(); expect( - createTestCommandRunner(command).run(const ['windows', '--no-pub']), + createTestCommandRunner(command) + .run(const ['windows', '--no-pub']), throwsToolExit(), ); }, @@ -154,10 +164,10 @@ void main() { setUpMockCoreProjectFiles(); expect( - createTestCommandRunner(command).run(const ['windows', '--no-pub']), + createTestCommandRunner(command) + .run(const ['windows', '--no-pub']), throwsToolExit( - message: - 'No Windows desktop project configured. See ' + message: 'No Windows desktop project configured. See ' 'https://flutter.dev/to/add-desktop-support ' 'to learn about adding Windows support to a project.', ), @@ -182,8 +192,10 @@ void main() { setUpMockProjectFilesForBuild(); expect( - createTestCommandRunner(command).run(const ['windows', '--no-pub']), - throwsToolExit(message: '"build windows" only supported on Windows hosts.'), + createTestCommandRunner(command) + .run(const ['windows', '--no-pub']), + throwsToolExit( + message: '"build windows" only supported on Windows hosts.'), ); }, overrides: { @@ -205,7 +217,8 @@ void main() { setUpMockProjectFilesForBuild(); expect( - createTestCommandRunner(command).run(const ['windows', '--no-pub']), + createTestCommandRunner(command) + .run(const ['windows', '--no-pub']), throwsToolExit( message: '"build windows" is not currently supported. To enable, run "flutter config --enable-windows-desktop".', @@ -235,7 +248,8 @@ void main() { buildCommand('Release', stdout: 'STDOUT STUFF'), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); expect(testLogger.statusText, isNot(contains('STDOUT STUFF'))); expect(testLogger.traceText, contains('STDOUT STUFF')); }, @@ -262,7 +276,8 @@ void main() { buildCommand('Release'), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); expect( analyticsTimingEventExists( @@ -332,7 +347,8 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif buildCommand('Release', stdout: stdout), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); // Just the warnings and errors should be surfaced. expect(testLogger.errorText, r''' C:\foo\windows\x64\runner\main.cpp(18): error C2220: the following warning is treated as an error [C:\foo\build\windows\x64\runner\test.vcxproj] @@ -365,7 +381,8 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif buildCommand('Release', verbose: true, stdout: 'STDOUT STUFF'), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub', '-v']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub', '-v']); expect(testLogger.statusText, contains('STDOUT STUFF')); expect(testLogger.traceText, isNot(contains('STDOUT STUFF'))); }, @@ -485,7 +502,8 @@ if %errorlevel% neq 0 goto :VCEnd assembleProject.createSync(recursive: true); assembleProject.writeAsStringSync(fakeBadProjectContent); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); final List projectLines = assembleProject.readAsLinesSync(); @@ -645,7 +663,8 @@ if %errorlevel% neq 0 goto :VCEnd await createTestCommandRunner( command, ).run(const ['windows', '--release', '--no-pub']); - expect(testLogger.statusText, contains(r'โœ“ Built build\windows\x64\runner\Release')); + expect(testLogger.statusText, + contains(r'โœ“ Built build\windows\x64\runner\Release')); }, overrides: { FileSystem: () => fileSystem, @@ -702,7 +721,8 @@ if %errorlevel% neq 0 goto :VCEnd buildCommand('Release'), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); final File cmakeConfig = fileSystem.currentDirectory .childDirectory('windows') @@ -750,7 +770,12 @@ if %errorlevel% neq 0 goto :VCEnd await createTestCommandRunner( command, - ).run(const ['windows', '--no-pub', '--build-name=1.2.3', '--build-number=4']); + ).run(const [ + 'windows', + '--no-pub', + '--build-name=1.2.3', + '--build-number=4' + ]); final File cmakeConfig = fileSystem.currentDirectory .childDirectory('windows') @@ -906,7 +931,12 @@ if %errorlevel% neq 0 goto :VCEnd await createTestCommandRunner( command, - ).run(const ['windows', '--no-pub', '--build-name=1.2.3', '--build-number=4']); + ).run(const [ + 'windows', + '--no-pub', + '--build-name=1.2.3', + '--build-number=4' + ]); final File cmakeConfig = fileSystem.currentDirectory .childDirectory('windows') @@ -954,7 +984,12 @@ if %errorlevel% neq 0 goto :VCEnd await createTestCommandRunner( command, - ).run(const ['windows', '--no-pub', '--build-name=1.2.3', '--build-number=hello']); + ).run(const [ + 'windows', + '--no-pub', + '--build-name=1.2.3', + '--build-number=hello' + ]); final File cmakeConfig = fileSystem.currentDirectory .childDirectory('windows') @@ -1011,7 +1046,12 @@ if %errorlevel% neq 0 goto :VCEnd await createTestCommandRunner( command, - ).run(const ['windows', '--no-pub', '--build-name=1.2.3', '--build-number=4.5']); + ).run(const [ + 'windows', + '--no-pub', + '--build-name=1.2.3', + '--build-number=4.5' + ]); final File cmakeConfig = fileSystem.currentDirectory .childDirectory('windows') @@ -1131,14 +1171,16 @@ if %errorlevel% neq 0 goto :VCEnd contains('A summary of your Windows bundle analysis can be found at'), ); expect(testLogger.statusText, contains('dart devtools --appSizeBase=')); - expect(fakeAnalytics.sentEvents, contains(Event.codeSizeAnalysis(platform: 'windows'))); + expect(fakeAnalytics.sentEvents, + contains(Event.codeSizeAnalysis(platform: 'windows'))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), FileSystem: () => fileSystem, ProcessManager: () => processManager, Platform: () => windowsPlatform, - FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), + FileSystemUtils: () => + FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), Analytics: () => fakeAnalytics, }, ); @@ -1155,12 +1197,14 @@ if %errorlevel% neq 0 goto :VCEnd logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils(), )..visualStudioOverride = fakeVisualStudio; - fileSystem.currentDirectory = fileSystem.directory("test_'path")..createSync(); + fileSystem.currentDirectory = fileSystem.directory("test_'path") + ..createSync(); final String absPath = fileSystem.currentDirectory.absolute.path; setUpMockCoreProjectFiles(); expect( - createTestCommandRunner(command).run(const ['windows', '--no-pub']), + createTestCommandRunner(command) + .run(const ['windows', '--no-pub']), throwsToolExit( message: 'Path $absPath contains invalid characters in "\'#!\$^&*=|,;<>?". ' @@ -1199,7 +1243,8 @@ No file or variants found for asset: images/a_dot_burr.jpeg. buildCommand('Release', stdout: stdout), ]); - await createTestCommandRunner(command).run(const ['windows', '--no-pub']); + await createTestCommandRunner(command) + .run(const ['windows', '--no-pub']); // Just the warnings and errors should be surfaced. expect(testLogger.errorText, r''' Error detected in pubspec.yaml: @@ -1213,6 +1258,39 @@ No file or variants found for asset: images/a_dot_burr.jpeg. FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), }, ); + + testUsingContext( + 'shorebird.yaml is updated when SHOREBIRD_PUBLIC_KEY env var is set', + () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final BuildWindowsCommand command = BuildWindowsCommand( + logger: BufferLogger.test(), + operatingSystemUtils: FakeOperatingSystemUtils()) + ..visualStudioOverride = fakeVisualStudio; + setUpMockProjectFilesForBuild(); + final File shorebirdYamlFile = fileSystem.file( + r'build\windows\x64\runner\Release\data\flutter_assets\shorebird.yaml', + ) + ..createSync(recursive: true) + ..writeAsStringSync('app_id: my-app-id'); + + processManager = FakeProcessManager.list([ + cmakeGenerationCommand(), + buildCommand('Release'), + ]); + + await createTestCommandRunner(command) + .run(const ['windows', '--release', '--no-pub']); + + final String updatedYaml = shorebirdYamlFile.readAsStringSync(); + expect(updatedYaml, contains('app_id: my-app-id')); + expect(updatedYaml, contains('patch_public_key: my_public_key')); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + Platform: () => windowsPlatformWithPublicKey, + FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), + }); } class FakeVisualStudio extends Fake implements VisualStudio { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart index 65ec94e110eaf..c379fe3f147b2 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart @@ -239,13 +239,18 @@ void main() { fakeFlutterVersion: FakeFlutterVersion(), ), ), - projectRoot: projectDir, + project: project, fs: fs, logger: logger, onChangeDetected: (_) {}, onPubspecChangeDetected: (String path) {}, ); - codeGenerator = PreviewCodeGenerator(widgetPreviewScaffoldProject: project, fs: fs); + codeGenerator = PreviewCodeGenerator( + widgetPreviewScaffoldProject: FlutterProject.fromDirectoryTest( + project.widgetPreviewScaffold, + ), + fs: fs, + ); final pub = Pub.test( fileSystem: fs, logger: logger, @@ -267,15 +272,15 @@ void main() { 'correctly generates ${PreviewCodeGenerator.getGeneratedPreviewFilePath(fs)}', () async { // Check that the generated preview file doesn't exist yet. - final File generatedPreviewFile = project.directory.childFile( + final File generatedPreviewFile = project.widgetPreviewScaffold.childFile( PreviewCodeGenerator.getGeneratedPreviewFilePath(fs), ); expect(generatedPreviewFile, isNot(exists)); + generatedPreviewFile.createSync(recursive: true); final PreviewDependencyGraph details = await previewDetector.initialize(); // Populate the generated preview file. codeGenerator.populatePreviewsInGeneratedPreviewScaffold(details); - expect(generatedPreviewFile, exists); const expectedGeneratedPreviewFileContents = ''' // ignore_for_file: implementation_imports @@ -385,7 +390,6 @@ List<_i1.WidgetPreview> previews() => [ codeGenerator.populatePreviewsInGeneratedPreviewScaffold( const {}, ); - expect(generatedPreviewFile, exists); // The generated file should only contain: // - An import of the widget preview library @@ -401,5 +405,29 @@ List<_i1.WidgetPreview> previews() => []; expect(generatedPreviewFile.readAsStringSync(), emptyGeneratedPreviewFileContents); }, ); + + testUsingContext( + 'correctly generates ${PreviewCodeGenerator.getGeneratedDtdConnectionInfoFilePath(fs)}', + () async { + // Check that the generated preview file doesn't exist yet. + final File generatedDtdConnectionInfoFile = project.widgetPreviewScaffold.childFile( + PreviewCodeGenerator.getGeneratedDtdConnectionInfoFilePath(fs), + ); + expect(generatedDtdConnectionInfoFile, isNot(exists)); + generatedDtdConnectionInfoFile.createSync(recursive: true); + + // Populate the DTD connection info. + final Uri dtdUri = Uri.parse('ws://localhost:1234'); + codeGenerator.populateDtdConnectionInfo(dtdUri); + + final expectedDtdConnectionInfo = + ''' +// ignore_for_file: implementation_imports + +const String kWidgetPreviewDtdUri = '$dtdUri'; +'''; + expect(generatedDtdConnectionInfoFile.readAsStringSync(), expectedDtdConnectionInfo); + }, + ); }); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_invalid_preview_applications_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_invalid_preview_applications_test.dart index 4a5d74c702b31..fcb2a62b91330 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_invalid_preview_applications_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_invalid_preview_applications_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; import 'package:test/test.dart'; import '../../../../src/common.dart'; -import '../../../../src/context.dart'; import '../utils/preview_details_matcher.dart'; import '../utils/preview_detector_test_utils.dart'; import '../utils/preview_project.dart'; @@ -94,18 +93,11 @@ void main() { // Note: we don't use a MemoryFileSystem since we don't have a way to // provide it to package:analyzer APIs without writing a significant amount // of wrapper logic. - late PreviewDetector previewDetector; late BasicProjectWithInvalidPreviews project; - setUp(() { - previewDetector = createTestPreviewDetector(); - }); - - tearDown(() async { - await previewDetector.dispose(); - }); - - testUsingContext('ignores invalid previews in existing files', () async { + testPreviewDetector('ignores invalid previews in existing files', ( + PreviewDetector previewDetector, + ) async { project = await BasicProjectWithInvalidPreviews.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: ['foo.dart'], @@ -115,7 +107,9 @@ void main() { expectContainsPreviews(mapping, project.matcherMapping); }); - testUsingContext('ignores invalid previews in updated files', () async { + testPreviewDetector('ignores invalid previews in updated files', ( + PreviewDetector previewDetector, + ) async { project = await BasicProjectWithInvalidPreviews.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], @@ -135,7 +129,9 @@ void main() { ); }); - testUsingContext('ignores invalid previews in newly added files', () async { + testPreviewDetector('ignores invalid previews in newly added files', ( + PreviewDetector previewDetector, + ) async { project = await BasicProjectWithInvalidPreviews.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_previews_non_const_params_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_previews_non_const_params_test.dart index 5882c95d309bf..adfc6cc4738c1 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_previews_non_const_params_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_previews_non_const_params_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; import 'package:test/test.dart'; import '../../../../src/common.dart'; -import '../../../../src/context.dart'; import '../utils/preview_details_matcher.dart'; import '../utils/preview_detector_test_utils.dart'; import '../utils/preview_project.dart'; @@ -83,18 +82,11 @@ void main() { // Note: we don't use a MemoryFileSystem since we don't have a way to // provide it to package:analyzer APIs without writing a significant amount // of wrapper logic. - late PreviewDetector previewDetector; late ProjectWithPreviewsWithNonConstParams project; - setUp(() { - previewDetector = createTestPreviewDetector(); - }); - - tearDown(() async { - await previewDetector.dispose(); - }); - - testUsingContext('ignores previews with non-const parameters in existing files', () async { + testPreviewDetector('ignores previews with non-const parameters in existing files', ( + PreviewDetector previewDetector, + ) async { project = await ProjectWithPreviewsWithNonConstParams.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: ['foo.dart'], @@ -104,7 +96,9 @@ void main() { expectContainsPreviews(mapping, project.matcherMapping); }); - testUsingContext('ignores previews with non-const parameters in updated files', () async { + testPreviewDetector('ignores previews with non-const parameters in updated files', ( + PreviewDetector previewDetector, + ) async { project = await ProjectWithPreviewsWithNonConstParams.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], @@ -124,7 +118,9 @@ void main() { ); }); - testUsingContext('ignores previews with non-const parameters in newly added files', () async { + testPreviewDetector('ignores previews with non-const parameters in newly added files', ( + PreviewDetector previewDetector, + ) async { project = await ProjectWithPreviewsWithNonConstParams.create( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_173895_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_173895_test.dart index 598032b8524f2..354cf4b6ff7f9 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_173895_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_173895_test.dart @@ -8,6 +8,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/widget_preview/analytics.dart'; import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; import 'package:test/fake.dart'; @@ -29,6 +30,9 @@ void main() { fs = MemoryFileSystem.test(style: FileSystemStyle.windows); watcher = FakeWatcher(); logger = BufferLogger.test(); + final FlutterProject project = FlutterProject.fromDirectoryTest( + fs.systemTempDirectory.createTempSync('root'), + ); previewDetector = PreviewDetector( // Explicitly set the platform to Windows. platform: FakePlatform(operatingSystem: 'windows'), @@ -40,7 +44,7 @@ void main() { fs: MemoryFileSystem.test(), ), ), - projectRoot: fs.systemTempDirectory.createTempSync('root'), + project: project, logger: logger, fs: fs, onChangeDetected: (_) {}, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_178317_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_178317_test.dart new file mode 100644 index 0000000000000..fad1645ccc487 --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_178317_test.dart @@ -0,0 +1,98 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/widget_preview/analytics.dart'; +import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; +import 'package:test/fake.dart'; +import 'package:watcher/watcher.dart'; + +import '../../../../src/common.dart'; +import '../../../../src/fakes.dart'; + +void main() { + group('$PreviewDetector', () { + late MemoryFileSystem fs; + late FlutterProject project; + late PreviewDetector previewDetector; + late FakeWatcher watcher; + late BufferLogger logger; + + var changeCounter = 0; + void onChangeDetected(_) { + changeCounter++; + } + + setUp(() { + fs = MemoryFileSystem.test( + style: const LocalPlatform().isWindows ? FileSystemStyle.windows : FileSystemStyle.posix, + ); + watcher = FakeWatcher(); + logger = BufferLogger.test(); + project = FlutterProject.fromDirectoryTest(fs.systemTempDirectory.createTempSync('root')); + previewDetector = PreviewDetector( + platform: FakePlatform(), + previewAnalytics: WidgetPreviewAnalytics( + analytics: getInitializedFakeAnalyticsInstance( + fakeFlutterVersion: FakeFlutterVersion(), + fs: fs, + ), + ), + project: project, + logger: logger, + fs: fs, + onChangeDetected: onChangeDetected, + onPubspecChangeDetected: onChangeDetected, + watcherBuilder: (_) => watcher, + ); + }); + + tearDown(() async { + await previewDetector.dispose(); + await watcher.close(); + }); + + String buildDartFilePathIn(Directory root) { + final String filePath = fs.path.join(root.path, 'foo.dart'); + root.childFile(filePath).createSync(recursive: true); + return filePath; + } + + test('regression test https://github.com/flutter/flutter/issues/178317', () async { + // Also regression test for https://github.com/flutter/flutter/issues/179008 + await previewDetector.initialize(); + expect(project.ephemeralDirectories, isNotEmpty); + for (final Directory dir in project.ephemeralDirectories) { + watcher.controller.add(WatchEvent(ChangeType.ADD, buildDartFilePathIn(dir))); + } + // Simulates the watcher detecting a change that doesn't have a valid analysis context. + watcher.controller.add(WatchEvent(ChangeType.ADD, fs.path.join('foo', 'bar.dart'))); + + // Changes to .dart sources under ephemeral directories or sources that don't have valid + // analysis contexts shouldn't trigger the change detection callback. + expect(changeCounter, 0); + }); + }); +} + +class FakeWatcher extends Fake implements Watcher { + final controller = StreamController(); + + @override + Stream get events => controller.stream; + + @override + bool get isReady => true; + + @override + Future get ready => Future.value(); + + Future close() => controller.close(); +} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_test.dart index a1a0161431422..d1f68711b8724 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_test.dart @@ -10,7 +10,6 @@ import 'package:test/test.dart'; import 'package:unified_analytics/unified_analytics.dart'; import '../../../../src/common.dart'; -import '../../../../src/context.dart'; import '../utils/preview_details_matcher.dart'; import '../utils/preview_detector_test_utils.dart'; import '../utils/preview_project.dart'; @@ -35,20 +34,10 @@ void main() { // Note: we don't use a MemoryFileSystem since we don't have a way to // provide it to package:analyzer APIs without writing a significant amount // of wrapper logic. - late PreviewDetector previewDetector; late ProjectWithPreviews project; - late FakeAnalytics analytics; - setUp(() { - previewDetector = createTestPreviewDetector(); - analytics = previewDetector.previewAnalytics.analytics as FakeAnalytics; - }); - - tearDown(() async { - await previewDetector.dispose(); - }); - - void expectNPreviewReloadTimingEvents(int n) { + void expectNPreviewReloadTimingEvents(PreviewDetector previewDetector, int n) { + final analytics = previewDetector.previewAnalytics.analytics as FakeAnalytics; expect(analytics.sentEvents, hasLength(n)); for (final Event event in analytics.sentEvents) { if (event.eventData case { @@ -67,7 +56,9 @@ void main() { 'previews': BasicProjectWithExhaustivePreviews.create, 'multipreviews': MultiPreviewProject.create, }.entries) { - testUsingContext('can detect $previewType in existing files', () async { + testPreviewDetector('can detect $previewType in existing files', ( + PreviewDetector previewDetector, + ) async { project = await createProject( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [ @@ -80,7 +71,9 @@ void main() { expect(mapping.nodesWithPreviews.keys, unorderedMatches(project.librariesWithPreviews)); }); - testUsingContext('can detect $previewType in updated files', () async { + testPreviewDetector('can detect $previewType in updated files', ( + PreviewDetector previewDetector, + ) async { // Create two files with existing previews and one without. project = await createProject( projectRoot: previewDetector.projectRoot, @@ -94,7 +87,7 @@ void main() { // Initialize the file watcher. final PreviewDependencyGraph initialPreviews = await previewDetector.initialize(); expectContainsPreviews(initialPreviews, project.matcherMapping); - expectNPreviewReloadTimingEvents(0); + expectNPreviewReloadTimingEvents(previewDetector, 0); await waitForChangeDetected( onChangeDetected: (PreviewDependencyGraph updated) { @@ -103,7 +96,7 @@ void main() { }, changeOperation: () => project.addPreviewContainingFile(path: 'baz.dart'), ); - expectNPreviewReloadTimingEvents(1); + expectNPreviewReloadTimingEvents(previewDetector, 1); // Update the file with an existing preview to remove the preview and ensure it triggers // the preview detector. @@ -114,10 +107,12 @@ void main() { }, changeOperation: () => project.addNonPreviewContainingFile(path: 'baz.dart'), ); - expectNPreviewReloadTimingEvents(2); + expectNPreviewReloadTimingEvents(previewDetector, 2); }); - testUsingContext('can detect $previewType in newly added files', () async { + testPreviewDetector('can detect $previewType in newly added files', ( + PreviewDetector previewDetector, + ) async { project = await createProject( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], @@ -129,7 +124,7 @@ void main() { // Initialize the file watcher. final PreviewDependencyGraph initialPreviews = await previewDetector.initialize(); expect(initialPreviews, expectedInitialMapping); - expectNPreviewReloadTimingEvents(0); + expectNPreviewReloadTimingEvents(previewDetector, 0); await waitForChangeDetected( onChangeDetected: (PreviewDependencyGraph updated) { @@ -139,10 +134,12 @@ void main() { // Create baz.dart, which contains previews. changeOperation: () => project.addPreviewContainingFile(path: 'baz.dart'), ); - expectNPreviewReloadTimingEvents(1); + expectNPreviewReloadTimingEvents(previewDetector, 1); }); - testUsingContext('can detect $previewType in existing libraries with parts', () async { + testPreviewDetector('can detect $previewType in existing libraries with parts', ( + PreviewDetector previewDetector, + ) async { project = await createProject( projectRoot: previewDetector.projectRoot, @@ -154,7 +151,9 @@ void main() { expect(mapping.nodesWithPreviews.keys, unorderedMatches(project.librariesWithPreviews)); }); - testUsingContext('can detect $previewType in newly added libraries with parts', () async { + testPreviewDetector('can detect $previewType in newly added libraries with parts', ( + PreviewDetector previewDetector, + ) async { project = await createProject( projectRoot: previewDetector.projectRoot, pathsWithPreviews: [], @@ -165,7 +164,7 @@ void main() { final PreviewDependencyGraph mapping = await previewDetector.initialize(); expect(mapping.nodesWithPreviews, expectedInitialMapping); - expectNPreviewReloadTimingEvents(0); + expectNPreviewReloadTimingEvents(previewDetector, 0); // Add a library with a part file, which will cause a change detected event for each file. await waitForNChangesDetected( @@ -176,11 +175,13 @@ void main() { previewDetector.dependencyGraph.nodesWithPreviews; expect(nodesWithPreviews, isNotEmpty); expect(nodesWithPreviews.keys, unorderedMatches(project.librariesWithPreviews)); - expectNPreviewReloadTimingEvents(2); + expectNPreviewReloadTimingEvents(previewDetector, 2); }); } - testUsingContext('can detect changes in the pubspec.yaml', () async { + testPreviewDetector('can detect changes in the pubspec.yaml', ( + PreviewDetector previewDetector, + ) async { // Create an initial pubspec. project = await BasicProjectWithExhaustivePreviews.create( projectRoot: previewDetector.projectRoot, @@ -196,7 +197,7 @@ void main() { await waitForPubspecChangeDetected(changeOperation: () => project.touchPubspec()); // There should be no reload timing events for a pubspec change. - expectNPreviewReloadTimingEvents(0); + expectNPreviewReloadTimingEvents(previewDetector, 0); }); }); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_workspace_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_workspace_test.dart index 6e71d1b9c0447..338b5c7bccb49 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_workspace_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_workspace_test.dart @@ -7,7 +7,6 @@ import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; import 'package:test/test.dart'; import '../../../../src/common.dart'; -import '../../../../src/context.dart'; import '../utils/preview_detector_test_utils.dart'; import '../utils/preview_project.dart'; @@ -19,21 +18,6 @@ import '../utils/preview_project.dart'; void main() { initializeTestPreviewDetectorState(); group('$PreviewDetector - Workspace', () { - // Note: we don't use a MemoryFileSystem since we don't have a way to - // provide it to package:analyzer APIs without writing a significant amount - // of wrapper logic. - late PreviewDetector previewDetector; - late WidgetPreviewWorkspace workspace; - - setUp(() { - previewDetector = createTestPreviewDetector(); - workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); - }); - - tearDown(() async { - await previewDetector.dispose(); - }); - const simplePreviewSource = ''' import 'package:flutter/material.dart'; import 'package:flutter/widget_previews.dart'; @@ -48,22 +32,25 @@ import 'package:flutter/material.dart'; Widget foo() => Text('Hello world!'); '''; - testUsingContext( - 'can detect previews in existing files in multiple workspace projects', - () async { - (await workspace.createWorkspaceProject( - name: 'foo', - )).writeFile((path: 'foo.dart', source: simplePreviewSource)); - (await workspace.createWorkspaceProject( - name: 'bar', - )).writeFile((path: 'bar.dart', source: simplePreviewSource)); - - final PreviewDependencyGraph mapping = await previewDetector.initialize(); - expect(mapping.nodesWithPreviews.length, 2); - }, - ); - - testUsingContext('can detect previews in updated files', () async { + testPreviewDetector('can detect previews in existing files in multiple workspace projects', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); + (await workspace.createWorkspaceProject( + name: 'foo', + )).writeFile((path: 'foo.dart', source: simplePreviewSource)); + (await workspace.createWorkspaceProject( + name: 'bar', + )).writeFile((path: 'bar.dart', source: simplePreviewSource)); + + final PreviewDependencyGraph mapping = await previewDetector.initialize(); + expect(mapping.nodesWithPreviews.length, 2); + }); + + testPreviewDetector('can detect previews in updated files', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); // Create two projects with existing previews and one without. (await workspace.createWorkspaceProject( name: 'foo', @@ -99,7 +86,10 @@ Widget foo() => Text('Hello world!'); ); }); - testUsingContext('can detect previews in newly added projects', () async { + testPreviewDetector('can detect previews in newly added projects', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); // Create two projects with existing previews. (await workspace.createWorkspaceProject( name: 'foo', @@ -124,7 +114,10 @@ Widget foo() => Text('Hello world!'); ); }); - testUsingContext('can detect previews removed due to deleted project', () async { + testPreviewDetector('can detect previews removed due to deleted project', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); // Create three projects with existing previews. (await workspace.createWorkspaceProject( name: 'foo', @@ -151,7 +144,10 @@ Widget foo() => Text('Hello world!'); ); }); - testUsingContext("can detect changes in a subproject's pubspec.yaml", () async { + testPreviewDetector("can detect changes in a subproject's pubspec.yaml", ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); // Create three empty projects in the same workspace. await workspace.createWorkspaceProject(name: 'foo'); await workspace.createWorkspaceProject(name: 'bar'); @@ -169,7 +165,10 @@ Widget foo() => Text('Hello world!'); ); }); - testUsingContext("can detect changes in a workspace's root pubspec.yaml", () async { + testPreviewDetector("can detect changes in a workspace's root pubspec.yaml", ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); // Create three empty projects in the same workspace. await workspace.createWorkspaceProject(name: 'foo'); await workspace.createWorkspaceProject(name: 'bar'); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_graph_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_graph_test.dart index c165b07303b7b..fe61c5dd22f76 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_graph_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_graph_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; import 'package:test/test.dart'; import '../../../src/common.dart'; -import '../../../src/context.dart'; import 'utils/preview_detector_test_utils.dart'; import 'utils/preview_project.dart'; @@ -26,20 +25,12 @@ void main() { // Note: we don't use a MemoryFileSystem since we don't have a way to // provide it to package:analyzer APIs without writing a significant amount // of wrapper logic. - late PreviewDetector previewDetector; - late WidgetPreviewProject project; - setUp(() async { - previewDetector = createTestPreviewDetector(); - project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + testPreviewDetector('dependency graph cycle smoke test', ( + PreviewDetector previewDetector, + ) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); await project.initializePubspec(); - }); - - tearDown(() async { - await previewDetector.dispose(); - }); - - testUsingContext('dependency graph cycle smoke test', () async { // Simple test to ensure graph cycles don't cause infinite recursion during traversal. [ (path: 'foo.dart', source: "import 'bar.dart';"), @@ -79,11 +70,12 @@ part of 'lib.dart'; ''', ); - setUp(() { - [main, lib, libPart1, libPart2].forEach(project.writeFile); - }); + final sources = [main, lib, libPart1, libPart2]; - testUsingContext('smoke test', () async { + testPreviewDetector('smoke test', (PreviewDetector previewDetector) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); // Ensure that projects with libraries containing parts are handled correctly. @@ -98,7 +90,10 @@ part of 'lib.dart'; expect(initialGraph[project.toPreviewPath(lib.path)]!.files, hasLength(3)); }); - testUsingContext('with errors in parts', () async { + testPreviewDetector('with errors in parts', (PreviewDetector previewDetector) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); expectPreviewDependencyGraphIsWellFormed(project: project, graph: initialGraph); @@ -141,14 +136,16 @@ void foo() => bar(); void bar() => null; ''', ); + + const sources = [main, foo, bar]; + WidgetPreviewSourceFile toInvalidSource(WidgetPreviewSourceFile original) => withUpdatedSource(original, 'invalid-symbol'); - setUp(() { - [main, foo, bar].forEach(project.writeFile); - }); - - testUsingContext('entire directory removed', () async { + testPreviewDetector('entire directory removed', (PreviewDetector previewDetector) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); String platformPath(List pathSegments) => pathSegments.join(const LocalPlatform().pathSeparator); final WidgetPreviewSourceFile a = ( @@ -190,7 +187,10 @@ void bar() => null; expectPreviewDependencyGraphIsWellFormed(project: project, graph: initialGraph); }); - testUsingContext('smoke test', () async { + testPreviewDetector('smoke test', (PreviewDetector previewDetector) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); expect(initialGraph.keys, containsAll(project.paths)); @@ -212,7 +212,12 @@ void bar() => null; await expectHasNoErrors(project: project, changeOperation: () => project.writeFile(bar)); }); - testUsingContext('file with error added and removed', () async { + testPreviewDetector('file with error added and removed', ( + PreviewDetector previewDetector, + ) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); expect(initialGraph.keys, containsAll(project.paths)); @@ -251,30 +256,32 @@ void bar() => null; await expectHasNoErrors(project: project, changeOperation: () => project.writeFile(main)); }); - testUsingContext( - 'error added into dependency in the middle of the graph and removed', - () async { - final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); - expect(initialGraph.keys, containsAll(project.paths)); - - // Verify there's no errors in the project. - for (final LibraryPreviewNode node in initialGraph.values) { - expect(node.dependencyHasErrors, false); - expect(node.hasErrors, false); - } - - // Add baz.dart, which contains errors. Since no other files import baz.dart, it should be - // the only file with errors. - await expectHasErrors( - project: project, - changeOperation: () => project.writeFile(toInvalidSource(foo)), - filesWithErrors: {foo, main}, - ); - - // Delete baz.dart. main.dart should continue to have an error. - await expectHasNoErrors(project: project, changeOperation: () => project.writeFile(foo)); - }, - ); + testPreviewDetector('error added into dependency in the middle of the graph and removed', ( + PreviewDetector previewDetector, + ) async { + final project = WidgetPreviewProject(projectRoot: previewDetector.projectRoot); + sources.forEach(project.writeFile); + await project.initializePubspec(); + final PreviewDependencyGraph initialGraph = await previewDetector.initialize(); + expect(initialGraph.keys, containsAll(project.paths)); + + // Verify there's no errors in the project. + for (final LibraryPreviewNode node in initialGraph.values) { + expect(node.dependencyHasErrors, false); + expect(node.hasErrors, false); + } + + // Add baz.dart, which contains errors. Since no other files import baz.dart, it should be + // the only file with errors. + await expectHasErrors( + project: project, + changeOperation: () => project.writeFile(toInvalidSource(foo)), + filesWithErrors: {foo, main}, + ); + + // Delete baz.dart. main.dart should continue to have an error. + await expectHasNoErrors(project: project, changeOperation: () => project.writeFile(foo)); + }); }); }); } diff --git a/packages/flutter_tools/test/general.shard/widget_preview/preview_manifest_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_test.dart similarity index 97% rename from packages/flutter_tools/test/general.shard/widget_preview/preview_manifest_test.dart rename to packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_test.dart index eae0bafd2495c..ee43851bf5c99 100644 --- a/packages/flutter_tools/test/general.shard/widget_preview/preview_manifest_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_test.dart @@ -14,10 +14,9 @@ import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/widget_preview/preview_manifest.dart'; import 'package:test/test.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; +import '../../../../src/common.dart'; +import '../../../../src/context.dart'; -// TODO(bkonyi): test pubspec change detection for workspaces void main() { group('$PreviewManifest', () { late FlutterProject rootProject; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_workspace_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_workspace_test.dart new file mode 100644 index 0000000000000..a82c163070254 --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_workspace_test.dart @@ -0,0 +1,133 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; +import 'package:flutter_tools/src/widget_preview/preview_manifest.dart'; +import 'package:test/test.dart'; + +import '../../../../src/common.dart'; +import '../utils/preview_detector_test_utils.dart'; +import '../utils/preview_project.dart'; + +// Note: this test isn't under the general.shard since tests under that directory +// have a 2000ms time out and these tests write to the real file system and watch +// directories for changes. This can be slow on heavily loaded machines and cause +// flaky failures. + +void main() { + initializeTestPreviewDetectorState(); + group('$PreviewManifest - Workspace', () { + testPreviewDetector('can handle workspace entries that do not exist', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); + + await workspace.createWorkspaceProject(name: 'foo'); + await workspace.createWorkspaceProject(name: 'bar'); + + final PreviewManifest manifest = createPreviewManifest()..generate(); + await previewDetector.initialize(); + + // Verify the manifest contains pubspec hashes for each pubspec in the workspace. + final Set originalWorkspacePubspecPaths = workspace.workspacePubspecPaths; + expect(manifest.pubspecHashes.keys, originalWorkspacePubspecPaths); + + // Add a new workspace project to the workspace pubspec, but don't actually create the + // project yet. + String pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => workspace.updatePubspec(injectNonExistentProject: 'baz'), + ); + + // Update the manifest and verify we haven't added any new pubspec hashes, since the new + // workspace project hasn't been created yet. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, originalWorkspacePubspecPaths); + + // Create the newly added workspace project. + pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => + workspace.createWorkspaceProject(name: 'baz', updateWorkspacePubspec: false), + ); + + // Update the manifest and verify that the new project now has a pubspec hash entry. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, workspace.workspacePubspecPaths); + }); + + testPreviewDetector( + 'can handle the addition of new workspace projects before the workspace pubspec is updated', + (PreviewDetector previewDetector) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); + + await workspace.createWorkspaceProject(name: 'foo'); + await workspace.createWorkspaceProject(name: 'bar'); + + final PreviewManifest manifest = createPreviewManifest()..generate(); + await previewDetector.initialize(); + + // Verify the manifest contains pubspec hashes for each pubspec in the workspace. + final Set originalWorkspacePubspecPaths = workspace.workspacePubspecPaths; + expect(manifest.pubspecHashes.keys, originalWorkspacePubspecPaths); + + // Add a new workspace project, but don't update the workspace's pubspec to include it + // yet. + String pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => + workspace.createWorkspaceProject(name: 'baz', updateWorkspacePubspec: false), + ); + + // Update the manifest and verify we haven't added any new pubspec hashes, since the new + // workspace project technically isn't part of the workspace yet. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, originalWorkspacePubspecPaths); + + // Update the workspace to include the newly added project. + pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => workspace.updatePubspec(), + ); + + // Update the manifest and verify that the new project now has a pubspec hash entry. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, workspace.workspacePubspecPaths); + }, + ); + + testPreviewDetector('can handle the removal of workspace projects', ( + PreviewDetector previewDetector, + ) async { + final workspace = WidgetPreviewWorkspace(workspaceRoot: previewDetector.projectRoot); + + await workspace.createWorkspaceProject(name: 'foo'); + await workspace.createWorkspaceProject(name: 'bar'); + + final PreviewManifest manifest = createPreviewManifest()..generate(); + await previewDetector.initialize(); + + // Verify the manifest contains pubspec hashes for each pubspec in the workspace. + final Set originalWorkspacePubspecPaths = workspace.workspacePubspecPaths; + expect(manifest.pubspecHashes.keys, originalWorkspacePubspecPaths); + + // Add a new workspace project, but don't update the workspace's pubspec to include it + // yet. + String pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => + workspace.deleteWorkspaceProject(name: 'bar', updateWorkspacePubspec: false), + ); + + // Update the manifest and verify we haven't added any new pubspec hashes, since the new + // workspace project technically isn't part of the workspace yet. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, workspace.workspacePubspecPaths); + + // Update the workspace to include the newly added project. + pubspecPath = await waitForPubspecChangeDetected( + changeOperation: () => workspace.updatePubspec(), + ); + + // Update the manifest and verify that the new project now has a pubspec hash entry. + manifest.updatePubspecHash(updatedPubspecPath: pubspecPath); + expect(manifest.pubspecHashes.keys, workspace.workspacePubspecPaths); + }); + }); +} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_pubspec_builder_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_pubspec_builder_test.dart index 12ab73b36ae94..0d98dc2a279f6 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_pubspec_builder_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_pubspec_builder_test.dart @@ -62,9 +62,7 @@ void main() { for (var i = 0; i < root.deferredComponents!.length; ++i) { expect( updated.deferredComponents![i].toString(), - PreviewPubspecBuilder.transformDeferredComponent( - root.deferredComponents![i], - ).toString(), + pubspecBuilder.transformDeferredComponent(root.deferredComponents![i]).toString(), ); } } @@ -133,6 +131,9 @@ flutter: logger: logger, )!; + @override + late final Directory directory = fileSystem.directory(projectRoot); + @override late FlutterProject widgetPreviewScaffoldProject = FakeFlutterProject( projectRoot: fileSystem.path.join(projectRoot, '.dart_tool', 'widget_preview_scaffold'), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/regress_176018_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/regress_176018_test.dart index 073e6eb51c3e6..c95e6a3c7f03d 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/regress_176018_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/regress_176018_test.dart @@ -92,9 +92,9 @@ dependencies: final yaml = loadYaml(rootProject.widgetPreviewScaffoldProject.pubspecFile.readAsStringSync()) as YamlMap; - const expectedDependencies = { - 'abcd': {'path': '../../packages/$kPackageProjectName'}, - 'example': {'path': '../../packages/$kExampleProjectName'}, + final expectedDependencies = { + 'abcd': {'path': packageProject.projectRoot.path}, + 'example': {'path': exampleProject.projectRoot.path}, }; // The generated pubspec.yaml should have path dependencies on both the package and example diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart index 5fc58bd4aadcb..1b13884af2629 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart @@ -10,11 +10,16 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/signals.dart'; +import 'package:flutter_tools/src/cache.dart'; +import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/widget_preview/analytics.dart'; import 'package:flutter_tools/src/widget_preview/dependency_graph.dart'; import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; +import 'package:flutter_tools/src/widget_preview/preview_manifest.dart'; +import 'package:meta/meta.dart'; import '../../../../src/common.dart'; +import '../../../../src/context.dart'; import '../../../../src/fakes.dart'; import 'preview_project.dart'; @@ -24,6 +29,7 @@ var _stateInitialized = false; void Function(PreviewDependencyGraph)? _onChangeDetectedImpl; void Function(String path)? _onPubspecChangeDetected; Directory? _projectRoot; + late FileSystem _fs; /// Registers setup and tear down logic for [PreviewDetector] tests. @@ -44,11 +50,37 @@ void initializeTestPreviewDetectorState() { _stateInitialized = true; } +@isTest +void testPreviewDetector( + String description, + FutureOr Function(PreviewDetector) testMethod, { + Map overrides = const {}, +}) { + testUsingContext( + description, + () async { + PreviewDetector? previewDetector; + try { + previewDetector = createTestPreviewDetector(); + await testMethod(previewDetector); + } finally { + await previewDetector?.dispose(); + } + }, + overrides: { + FlutterProjectFactory: () => + FlutterProjectFactory(fileSystem: _fs, logger: BufferLogger.test()), + }, + ); +} + PreviewDetector createTestPreviewDetector() { if (!_stateInitialized) { throw StateError('$initializeTestPreviewDetectorState was not called!'); } _projectRoot = _fs.systemTempDirectory.createTempSync('root'); + final FlutterProject project = FlutterProject.fromDirectory(_projectRoot!); + return PreviewDetector( platform: FakePlatform(), previewAnalytics: WidgetPreviewAnalytics( @@ -59,7 +91,7 @@ PreviewDetector createTestPreviewDetector() { fs: MemoryFileSystem.test(), ), ), - projectRoot: _projectRoot!, + project: project, logger: BufferLogger.test(), fs: _fs, onChangeDetected: _onChangeDetectedRoot, @@ -67,6 +99,18 @@ PreviewDetector createTestPreviewDetector() { ); } +PreviewManifest createPreviewManifest() { + if (!_stateInitialized) { + throw StateError('$initializeTestPreviewDetectorState was not called!'); + } + return PreviewManifest( + logger: BufferLogger.test(), + rootProject: FlutterProject.fromDirectory(_projectRoot!), + fs: _fs, + cache: Cache.test(processManager: FakeProcessManager.any()), + ); +} + void _onChangeDetectedRoot(PreviewDependencyGraph mapping) { _onChangeDetectedImpl!(mapping); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_project.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_project.dart index 7050517c13801..1eb2094ecae3b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_project.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_project.dart @@ -26,6 +26,17 @@ class WidgetPreviewWorkspace { final Directory _packagesRoot; final File _pubspecYaml; + /// The set of directories that make up the workspace, including the workspace root. + Set get workspaceDirectories => { + workspaceRoot, + ..._packages.values.map((e) => e.projectRoot), + }; + + /// The set of paths to each pubspec in the workspace. + Set get workspacePubspecPaths => workspaceDirectories + .map((e) => workspaceRoot.fileSystem.path.join(e.path, 'pubspec.yaml')) + .toSet(); + final _packages = {}; /// The absolute path to the workspace's pubspec.yaml. @@ -36,7 +47,10 @@ class WidgetPreviewWorkspace { _pubspecYaml.setLastModifiedSync(DateTime.now()); } - Future createWorkspaceProject({required String name}) async { + Future createWorkspaceProject({ + required String name, + bool updateWorkspacePubspec = true, + }) async { if (_packages.containsKey(name)) { throw StateError('Project with name "$name" already exists.'); } @@ -45,23 +59,30 @@ class WidgetPreviewWorkspace { inWorkspace: true, packageName: name, ); - project.writePubspec(project.initialPubspecContents); _packages[name] = project; - await _updatePubspec(); + project.writePubspec(project.initialPubspecContents); + if (updateWorkspacePubspec) { + await updatePubspec(); + } return project; } - Future deleteWorkspaceProject({required String name}) async { + Future deleteWorkspaceProject({ + required String name, + bool updateWorkspacePubspec = true, + }) async { if (!_packages.containsKey(name)) { throw StateError('Project with name "$name" does not exist.'); } - _packages[name]!.projectRoot.deleteSync(recursive: true); - await _updatePubspec(); + _packages.remove(name)!.projectRoot.deleteSync(recursive: true); + if (updateWorkspacePubspec) { + await updatePubspec(); + } } - Future _updatePubspec() async { + Future updatePubspec({String? injectNonExistentProject}) async { final pubspec = StringBuffer('workspace:\n'); - for (final String package in _packages.keys) { + for (final String package in [..._packages.keys, ?injectNonExistentProject]) { pubspec.writeln(' - packages/$package'); } _pubspecYaml.writeAsStringSync(pubspec.toString()); @@ -70,7 +91,7 @@ class WidgetPreviewWorkspace { await savePackageConfig( PackageConfig( [ - for (final String package in _packages.keys) + for (final String package in [..._packages.keys, ?injectNonExistentProject]) Package(package, workspaceRoot.childDirectory('packages').childDirectory(package).uri), Package( 'flutter', diff --git a/packages/flutter_tools/test/commands.shard/permeable/widget_preview/preview_detector_regression_178472_test.dart b/packages/flutter_tools/test/commands.shard/permeable/widget_preview/preview_detector_regression_178472_test.dart new file mode 100644 index 0000000000000..37253f1601d0e --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/permeable/widget_preview/preview_detector_regression_178472_test.dart @@ -0,0 +1,99 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/widget_preview/analytics.dart'; +import 'package:flutter_tools/src/widget_preview/dependency_graph.dart'; +import 'package:flutter_tools/src/widget_preview/preview_detector.dart'; +import 'package:test/fake.dart'; +import 'package:watcher/watcher.dart'; + +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; + +void main() { + group('$PreviewDetector regression test https://github.com/flutter/flutter/issues/178472 -', () { + late LocalFileSystem fs; + late FlutterProject project; + late PreviewDetector previewDetector; + late FakeWatcher watcher; + late BufferLogger logger; + + setUp(() { + fs = LocalFileSystem.test(signals: FakeSignals()); + watcher = FakeWatcher(); + logger = BufferLogger.test(); + project = FlutterProject.fromDirectoryTest(fs.systemTempDirectory.createTempSync('root')); + previewDetector = PreviewDetector( + platform: FakePlatform(), + previewAnalytics: WidgetPreviewAnalytics( + analytics: getInitializedFakeAnalyticsInstance( + fakeFlutterVersion: FakeFlutterVersion(), + // We don't care about analytics in this test, so don't worry about having to + // provide a local file system. + fs: MemoryFileSystem.test(), + ), + ), + project: project, + logger: logger, + fs: fs, + onChangeDetected: (_) {}, + onPubspecChangeDetected: (_) {}, + watcherBuilder: (_) => watcher, + ); + }); + + tearDown(() async { + // Don't explicitly tear down the previewDetector as we've already disposed + // the underlying analysis context collection. If we try and dispose it again, + // we'll hang. + await watcher.close(); + }); + + test('do not throw when watch event is sent after the analysis context is disposed', () async { + final File file = project.directory.childDirectory('lib').childFile('foo.dart') + ..createSync(recursive: true); + final String filePath = file.path; + await previewDetector.initialize(); + await previewDetector.collection.dispose(); + watcher.controller.add(WatchEvent(ChangeType.ADD, filePath)); + }); + + test( + 'do not throw when findPreviewFunctions is invoked after the analysis context is disposed', + () async { + final File file = project.directory.childDirectory('lib').childFile('foo.dart') + ..createSync(recursive: true); + await previewDetector.initialize(); + await previewDetector.collection.dispose(); + final PreviewDependencyGraph result = await previewDetector.mutex.runGuarded( + () => previewDetector.findPreviewFunctions(file), + ); + expect(result.entries, isEmpty); + }, + ); + }); +} + +class FakeWatcher extends Fake implements Watcher { + final controller = StreamController(); + + @override + Stream get events => controller.stream; + + @override + bool get isReady => true; + + @override + Future get ready => Future.value(); + + Future close() => controller.close(); +} diff --git a/packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart b/packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart index 30112f186eacb..33289a8c8eb68 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart @@ -19,6 +19,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/widget_preview.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/web/web_device.dart'; @@ -149,10 +150,6 @@ void main() { return fs.directory(await createProject(tempDir, arguments: ['--pub'])); } - Directory widgetPreviewScaffoldFromRootProject({required Directory rootProject}) { - return rootProject.childDirectory('.dart_tool').childDirectory('widget_preview_scaffold'); - } - Future runWidgetPreviewCommand(List arguments) async { final CommandRunner runner = createTestCommandRunner( WidgetPreviewCommand( @@ -210,15 +207,12 @@ void main() { '--verbose', ?rootProject?.path, ]); - final Directory widgetPreviewScaffoldDir = widgetPreviewScaffoldFromRootProject( - rootProject: rootProject ?? current, - ); // Don't perform analysis on Windows since `dart pub add` will use '\' for // path dependencies and cause analysis to fail. // TODO(bkonyi): enable analysis on Windows once https://github.com/dart-lang/pub/issues/4520 // is resolved. if (!platform.isWindows) { - await analyzeProject(widgetPreviewScaffoldDir.path); + await analyzeProject(WidgetPreviewStartCommand.widgetPreviewScaffold.path); } fs.currentDirectory = current; } @@ -265,8 +259,64 @@ void main() { } expectNoPreviewLaunchTimingEvents(); }); + + testUsingContext( + 'Flutter Web is disabled', + () async { + try { + await startWidgetPreview(rootProject: await createRootProject()); + fail('Successfully executed with Flutter Web disabled.'); + } on ToolExit catch (e) { + expect( + e.message, + 'Error: Widget Previews requires Flutter Web to be enabled. Please run ' + "'flutter config --enable-web' to enable Flutter Web and try again.", + ); + } + expectNoPreviewLaunchTimingEvents(); + }, + overrides: { + FeatureFlags: () => TestFeatureFlags( + // ignore: avoid_redundant_argument_values, readability + isWebEnabled: false, + ), + Pub: () => Pub.test( + fileSystem: fs, + logger: logger, + processManager: loggingProcessManager, + botDetector: botDetector, + platform: platform, + stdio: mockStdio, + ), + }, + ); }); + testUsingContext( + 'start succeeds when no .dart_tool/ directory exists', + () async { + // Regression test for https://github.com/flutter/flutter/issues/178052 + final Directory rootProject = await createRootProject(); + rootProject.childDirectory('.dart_tool').deleteSync(recursive: true); + await startWidgetPreview(rootProject: rootProject); + expectSinglePreviewLaunchTimingEvent(); + }, + overrides: { + Analytics: () => fakeAnalytics, + DeviceManager: () => fakeDeviceManager, + FileSystem: () => fs, + ProcessManager: () => loggingProcessManager, + Pub: () => Pub.test( + fileSystem: fs, + logger: logger, + processManager: loggingProcessManager, + botDetector: botDetector, + platform: platform, + stdio: mockStdio, + ), + }, + ); + testUsingContext( 'start creates .dart_tool/widget_preview_scaffold', () async { @@ -347,19 +397,17 @@ List<_i1.WidgetPreview> previews() => [ 'start finds existing previews and injects them into ${PreviewCodeGenerator.getGeneratedPreviewFilePath(fs)}', () async { final Directory rootProject = await createRootProject(); - final Directory widgetPreviewScaffoldDir = widgetPreviewScaffoldFromRootProject( - rootProject: rootProject, - ); rootProject .childDirectory('lib') .childFile('foo.dart') .writeAsStringSync(samplePreviewFile); - final File generatedFile = widgetPreviewScaffoldDir.childFile( + await startWidgetPreview(rootProject: rootProject); + + final File generatedFile = WidgetPreviewStartCommand.widgetPreviewScaffold.childFile( PreviewCodeGenerator.getGeneratedPreviewFilePath(fs), ); - await startWidgetPreview(rootProject: rootProject); expect(generatedFile.readAsStringSync().stripScriptUris, expectedGeneratedFileContents); expectSinglePreviewLaunchTimingEvent(); }, @@ -381,23 +429,19 @@ List<_i1.WidgetPreview> previews() => [ 'start finds existing previews in the CWD and injects them into ${PreviewCodeGenerator.getGeneratedPreviewFilePath(fs)}', () async { final Directory rootProject = await createRootProject(); - final Directory widgetPreviewScaffoldDir = widgetPreviewScaffoldFromRootProject( - rootProject: rootProject, - ); rootProject .childDirectory('lib') .childFile('foo.dart') .writeAsStringSync(samplePreviewFile); - final File generatedFile = widgetPreviewScaffoldDir.childFile( - PreviewCodeGenerator.getGeneratedPreviewFilePath(fs), - ); - // Try to execute using the CWD. - fs.currentDirectory = rootProject; await startWidgetPreview(rootProject: null); + final File generatedFile = WidgetPreviewStartCommand.widgetPreviewScaffold.childFile( + PreviewCodeGenerator.getGeneratedPreviewFilePath(fs), + ); + expect(generatedFile.readAsStringSync().stripScriptUris, expectedGeneratedFileContents); expectSinglePreviewLaunchTimingEvent(); }, diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index 33dc532022ba8..d0b327162b65e 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -55,6 +55,8 @@ void main() { usageOfV1EmbeddingReferencesHandler, jlinkErrorWithJava21AndSourceCompatibility, missingNdkSourcePropertiesFile, + applyingKotlinAndroidPluginErrorHandler, + useNewAgpDslErrorHandler, incompatibleKotlinVersionHandler, ]), ); @@ -1000,7 +1002,7 @@ A problem occurred evaluating project ':app'. 'โ”‚ To fix this issue, replace the following content: โ”‚\n' 'โ”‚ /android/build.gradle: โ”‚\n' "โ”‚ - classpath 'com.android.tools.build:gradle:' โ”‚\n" - "โ”‚ + classpath 'com.android.tools.build:gradle:$templateAndroidGradlePluginVersion' โ”‚\n" + "โ”‚ + classpath 'com.android.tools.build:gradle:$templateAndroidGradlePluginVersion' โ”‚\n" 'โ”‚ /android/gradle/wrapper/gradle-wrapper.properties: โ”‚\n' 'โ”‚ - https://services.gradle.org/distributions/gradle--all.zip โ”‚\n' 'โ”‚ + https://services.gradle.org/distributions/gradle-$templateDefaultGradleVersion-all.zip โ”‚\n' @@ -1621,6 +1623,86 @@ A problem occurred configuring project ':app'. ProcessManager: () => processManager, }, ); + + testUsingContext( + 'Failure to apply kotlin-android plugin', + () async { + const applyingKotlinAndroidPluginErrorExample = r''' +FAILURE: Build failed with an exception. + +* Where: +Build file '/Users/jesswon/Desktop/fresh_flutter_app/android/app/build.gradle.kts' + +* What went wrong: +An exception occurred applying plugin request [id: 'kotlin-android'] +> Failed to apply plugin 'kotlin-android'. + > โ›” Failed to apply plugin 'com.jetbrains.kotlin.android' + The 'org.jetbrains.kotlin.android' plugin is no longer required for Kotlin support since AGP 9.0. + Solution: Remove the 'org.jetbrains.kotlin.android' plugin from this project's build file: app/build.gradle.kts. + See https://issuetracker.google.com/438678642 for more details. + > java.lang.Throwable (no error message) + '''; + + final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); + await applyingKotlinAndroidPluginErrorHandler.handler( + line: applyingKotlinAndroidPluginErrorExample, + project: project, + usesAndroidX: true, + ); + + expect( + testLogger.statusText, + contains('Starting AGP 9+, the default has become built-in Kotlin.'), + ); + expect(testLogger.statusText, contains('This results in a build failure')); + expect(testLogger.statusText, contains('when applying the kotlin-android plugin')); + }, + overrides: { + GradleUtils: () => FakeGradleUtils(), + Platform: () => fakePlatform('android'), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }, + ); + + testUsingContext( + 'Failure to apply kotlin-android plugin', + () async { + const useNewAgpDslErrorHandlerExample = r''' +FAILURE: Build failed with an exception. + +* Where: +Build file '/Users/jesswon/Desktop/fresh_flutter_app/android/app/build.gradle.kts' + +* What went wrong: +An exception occurred applying plugin request [id: 'dev.flutter.flutter-gradle-plugin'] +> Failed to apply plugin 'dev.flutter.flutter-gradle-plugin'. + > java.lang.NullPointerException (no error message) + '''; + + final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); + await useNewAgpDslErrorHandler.handler( + line: useNewAgpDslErrorHandlerExample, + project: project, + usesAndroidX: true, + ); + + expect( + testLogger.statusText, + contains('Starting AGP 9+, only the new DSL interface will be read.'), + ); + expect(testLogger.statusText, contains('This results in a build failure')); + expect(testLogger.statusText, contains('when applying the Flutter Gradle plugin')); + expect(testLogger.statusText, contains('If you are not upgrading to AGP 9+')); + expect(testLogger.statusText, contains('run `flutter analyze --suggestions`')); + }, + overrides: { + GradleUtils: () => FakeGradleUtils(), + Platform: () => fakePlatform('android'), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }, + ); } bool formatTestErrorMessage(String errorMessage, GradleHandledError error) { diff --git a/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart index abd837fe3e3d6..c38495ea10e05 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/base/common.dart' show ToolExit; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/base/version_range.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/project.dart'; @@ -1002,8 +1003,7 @@ pluginManagement { KgpAgpTestData( true, kgpVersion: templateKotlinGradlePluginVersion, - // TODO(reidbaker): Replace with templateAndroidGradlePluginVersion - agpVersion: '8.7.2', + agpVersion: templateAndroidGradlePluginVersion, ), // Kotlin version at the edge of support window. @@ -1199,6 +1199,44 @@ pluginManagement { }); }); + testWithoutContext('agp versions validation', () { + final Version? parsedTemplateAndroidGradlePluginVersion = Version.parse( + templateAndroidGradlePluginVersion, + ); + final Version? parsedMaxKnownAgpVersionWithFullKotlinSupport = Version.parse( + maxKnownAgpVersionWithFullKotlinSupport, + ); + final Version? parsedMaxKnownAndSupportedAgpVersion = Version.parse( + maxKnownAndSupportedAgpVersion, + ); + final Version? parsedMaxKnownAgpVersion = Version.parse(maxKnownAgpVersion); + + expect( + parsedTemplateAndroidGradlePluginVersion! <= parsedMaxKnownAgpVersionWithFullKotlinSupport!, + isTrue, + reason: + 'Template AGP version ($parsedTemplateAndroidGradlePluginVersion) ' + 'is higher than maxKnownAgpVersionWithFullKotlinSupport ($parsedMaxKnownAgpVersionWithFullKotlinSupport). ' + 'Please update the maxKnownAgpVersionWithFullKotlinSupport', + ); + expect( + parsedMaxKnownAndSupportedAgpVersion! <= parsedMaxKnownAgpVersion!, + isTrue, + reason: + 'maxKnownAndSupportedAgpVersion ($parsedMaxKnownAndSupportedAgpVersion) ' + 'is higher than maxKnownAgpVersion ($parsedMaxKnownAgpVersion). ' + 'Please update the maxKnownAgpVersion', + ); + expect( + parsedMaxKnownAgpVersionWithFullKotlinSupport < parsedMaxKnownAgpVersion, + isTrue, + reason: + 'maxKnownAgpVersionWithFullKotlinSupport ($parsedMaxKnownAgpVersionWithFullKotlinSupport) ' + 'is higher than or equal to maxKnownAgpVersion ($parsedMaxKnownAgpVersion). ' + 'Please update the maxKnownAgpVersion', + ); + }); + group('getGradleVersionForAndroidPlugin', () { late FileSystem fileSystem; late Logger testLogger; diff --git a/packages/flutter_tools/test/general.shard/base/build_test.dart b/packages/flutter_tools/test/general.shard/base/build_test.dart index de41b2e569322..90cc0c26ac1db 100644 --- a/packages/flutter_tools/test/general.shard/base/build_test.dart +++ b/packages/flutter_tools/test/general.shard/base/build_test.dart @@ -37,6 +37,17 @@ const kDefaultClang = [ 'build/foo/snapshot_assembly.o', ]; +// Shorebird link info arguments added for iOS/macOS builds. +// These correspond to the dumpLinkInfoArgs in AOTSnapshotter.build(). +const kLinkInfoArgs = [ + '--print_class_table_link_debug_info_to=build/App.class_table.json', + '--print_class_table_link_info_to=build/App.ct.link', + '--print_field_table_link_debug_info_to=build/App.field_table.json', + '--print_field_table_link_info_to=build/App.ft.link', + '--print_dispatch_table_link_debug_info_to=build/App.dispatch_table.json', + '--print_dispatch_table_link_info_to=build/App.dt.link', +]; + void main() { group('GenSnapshot', () { late GenSnapshot genSnapshot; @@ -203,6 +214,7 @@ void main() { command: [ genSnapshotPath, '--deterministic', + ...kLinkInfoArgs, '--snapshot_kind=app-aot-assembly', '--assembly=$assembly', '--dwarf-stack-traces', @@ -278,6 +290,7 @@ void main() { command: [ genSnapshotPath, '--deterministic', + ...kLinkInfoArgs, '--snapshot_kind=app-aot-assembly', '--assembly=$assembly', '--obfuscate', @@ -349,6 +362,7 @@ void main() { command: [ genSnapshotPath, '--deterministic', + ...kLinkInfoArgs, '--snapshot_kind=app-aot-assembly', '--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}', 'main.dill', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 2e0f99300c3be..c0dda6b07591e 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -25,6 +25,17 @@ const kBoundaryKey = '4d2d9609-c662-4571-afde-31410f96caa6'; const kElfAot = '--snapshot_kind=app-aot-elf'; const kAssemblyAot = '--snapshot_kind=app-aot-assembly'; +/// Generate Shorebird link info arguments for iOS/macOS AOT builds. +/// The [buildPath] should be the build directory path (outputDir.parent.path). +List linkInfoArgsFor(String buildPath) => [ + '--print_class_table_link_debug_info_to=$buildPath/App.class_table.json', + '--print_class_table_link_info_to=$buildPath/App.ct.link', + '--print_field_table_link_debug_info_to=$buildPath/App.field_table.json', + '--print_field_table_link_info_to=$buildPath/App.ft.link', + '--print_dispatch_table_link_debug_info_to=$buildPath/App.dispatch_table.json', + '--print_dispatch_table_link_info_to=$buildPath/App.dt.link', +]; + final Platform macPlatform = FakePlatform( operatingSystem: 'macos', environment: {}, @@ -803,6 +814,7 @@ void main() { // This path is not known by the cache due to the iOS gen_snapshot split. 'Artifact.genSnapshotArm64.TargetPlatform.ios.profile', '--deterministic', + ...linkInfoArgsFor(build), '--write-v8-snapshot-profile-to=code_size_1/snapshot.arm64.json', '--trace-precompiler-to=code_size_1/trace.arm64.json', kAssemblyAot, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/hook_runner_native_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/hook_runner_native_test.dart new file mode 100644 index 0000000000000..d74b6ed1e6c37 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/build_system/targets/hook_runner_native_test.dart @@ -0,0 +1,55 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/build_system/targets/hook_runner_native.dart'; + +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/test_build_system.dart'; + +void main() { + late FileSystem fs; + + setUp(() { + fs = MemoryFileSystem.test(); + }); + + testUsingContext( + 'FlutterHookRunnerNative uses a separate output directory', + () async { + final hookRunner = FlutterHookRunnerNative(); + final environment = Environment.test( + fs.currentDirectory, + processManager: FakeProcessManager.any(), + artifacts: Artifacts.test(), + fileSystem: fs, + logger: BufferLogger.test(), + platform: FakePlatform(), + defines: {}, + ); + + await hookRunner.runHooks( + targetPlatform: TargetPlatform.linux_x64, + environment: environment, + logger: environment.logger, + ); + }, + overrides: { + BuildSystem: () => + TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) { + expect( + fs.path.basename(environment.outputDir.path), + FlutterHookRunnerNative.kHooksOutputDirectory, + ); + }), + }, + ); +} diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index aa31e06bfcddd..d57c76c444c7f 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart @@ -20,6 +20,17 @@ import '../../../src/fake_process_manager.dart'; import '../../../src/fakes.dart'; import '../../../src/package_config.dart'; +/// Generate Shorebird link info arguments for iOS/macOS AOT builds. +/// The [buildPath] should be the build directory path (outputDir.parent.path). +List linkInfoArgsFor(String buildPath) => [ + '--print_class_table_link_debug_info_to=$buildPath/App.class_table.json', + '--print_class_table_link_info_to=$buildPath/App.ct.link', + '--print_field_table_link_debug_info_to=$buildPath/App.field_table.json', + '--print_field_table_link_info_to=$buildPath/App.ft.link', + '--print_dispatch_table_link_debug_info_to=$buildPath/App.dispatch_table.json', + '--print_dispatch_table_link_info_to=$buildPath/App.dt.link', +]; + void main() { late Environment environment; late MemoryFileSystem fileSystem; @@ -142,7 +153,14 @@ void main() { ); lipoExtractX86_64Command = FakeCommand( - command: ['lipo', '-output', binary.path, '-extract', 'x86_64', binary.path], + command: [ + 'lipo', + '-output', + binary.path, + '-extract', + 'x86_64', + binary.path + ], ); }); @@ -229,7 +247,8 @@ void main() { isException.having( (Exception exception) => exception.toString(), 'description', - contains('FlutterMacOS.framework/Versions/A/FlutterMacOS does not exist, cannot thin'), + contains( + 'FlutterMacOS.framework/Versions/A/FlutterMacOS does not exist, cannot thin'), ), ), ); @@ -249,7 +268,13 @@ void main() { copyFrameworkCommand, lipoInfoFatCommand, FakeCommand( - command: ['lipo', binary.path, '-verify_arch', 'arm64', 'x86_64'], + command: [ + 'lipo', + binary.path, + '-verify_arch', + 'arm64', + 'x86_64' + ], exitCode: 1, ), ]); @@ -285,7 +310,8 @@ void main() { expect( logger.traceText, - contains('Skipping lipo for non-fat file /FlutterMacOS.framework/Versions/A/FlutterMacOS'), + contains( + 'Skipping lipo for non-fat file /FlutterMacOS.framework/Versions/A/FlutterMacOS'), ); }); @@ -313,7 +339,8 @@ void main() { lipoVerifyX86_64Command, ]); - await const ReleaseUnpackMacOS().build(environment..defines[kBuildMode] = 'release'); + await const ReleaseUnpackMacOS() + .build(environment..defines[kBuildMode] = 'release'); expect(processManager, hasNoRemainingExpectations); }, @@ -335,7 +362,8 @@ void main() { copyFrameworkDsymCommand, ]); - await const ReleaseUnpackMacOS().build(environment..defines[kBuildMode] = 'release'); + await const ReleaseUnpackMacOS() + .build(environment..defines[kBuildMode] = 'release'); expect(processManager, hasNoRemainingExpectations); }, @@ -372,7 +400,8 @@ void main() { ]); await expectLater( - const ReleaseUnpackMacOS().build(environment..defines[kBuildMode] = 'release'), + const ReleaseUnpackMacOS() + .build(environment..defines[kBuildMode] = 'release'), throwsA( isException.having( (Exception exception) => exception.toString(), @@ -393,15 +422,19 @@ void main() { () async { fileSystem .directory( - artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: BuildMode.debug), + artifacts.getArtifactPath(Artifact.flutterMacOSFramework, + mode: BuildMode.debug), ) .createSync(); - final String inputKernel = fileSystem.path.join(environment.buildDir.path, 'app.dill'); + final String inputKernel = + fileSystem.path.join(environment.buildDir.path, 'app.dill'); fileSystem.file(inputKernel) ..createSync(recursive: true) ..writeAsStringSync('testing'); - expect(() async => const DebugMacOSBundleFlutterAssets().build(environment), throwsException); + expect( + () async => const DebugMacOSBundleFlutterAssets().build(environment), + throwsException); }, overrides: { FileSystem: () => fileSystem, @@ -414,7 +447,8 @@ void main() { () async { fileSystem .directory( - artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: BuildMode.debug), + artifacts.getArtifactPath(Artifact.flutterMacOSFramework, + mode: BuildMode.debug), ) .createSync(); fileSystem @@ -447,20 +481,25 @@ void main() { expect( fileSystem - .file('App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin') + .file( + 'App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin') .readAsStringSync(), 'testing', ); expect( - fileSystem.file('App.framework/Versions/A/Resources/Info.plist').readAsStringSync(), + fileSystem + .file('App.framework/Versions/A/Resources/Info.plist') + .readAsStringSync(), contains('io.flutter.flutter.app'), ); expect( - fileSystem.file('App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'), + fileSystem.file( + 'App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'), exists, ); expect( - fileSystem.file('App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'), + fileSystem.file( + 'App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'), exists, ); }, @@ -563,23 +602,30 @@ void main() { fileSystem .file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') .createSync(recursive: true); - fileSystem.file('${environment.buildDir.path}/App.framework/App').createSync(recursive: true); - fileSystem.file('${environment.buildDir.path}/native_assets.json').createSync(); + fileSystem + .file('${environment.buildDir.path}/App.framework/App') + .createSync(recursive: true); + fileSystem + .file('${environment.buildDir.path}/native_assets.json') + .createSync(); await const ProfileMacOSBundleFlutterAssets().build( environment..defines[kBuildMode] = 'profile', ); expect( - fileSystem.file('App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin'), + fileSystem.file( + 'App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin'), isNot(exists), ); expect( - fileSystem.file('App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'), + fileSystem.file( + 'App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'), isNot(exists), ); expect( - fileSystem.file('App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'), + fileSystem.file( + 'App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'), isNot(exists), ); }, @@ -598,17 +644,23 @@ void main() { fileSystem .file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') .createSync(recursive: true); - fileSystem.file('${environment.buildDir.path}/App.framework/App').createSync(recursive: true); fileSystem - .file('${environment.buildDir.path}/App.framework.dSYM/Contents/Resources/DWARF/App') + .file('${environment.buildDir.path}/App.framework/App') .createSync(recursive: true); - fileSystem.file('${environment.buildDir.path}/native_assets.json').createSync(); + fileSystem + .file( + '${environment.buildDir.path}/App.framework.dSYM/Contents/Resources/DWARF/App') + .createSync(recursive: true); + fileSystem + .file('${environment.buildDir.path}/native_assets.json') + .createSync(); await const ReleaseMacOSBundleFlutterAssets().build( environment..defines[kBuildMode] = 'release', ); - expect(fileSystem.file('App.framework.dSYM/Contents/Resources/DWARF/App'), exists); + expect(fileSystem.file('App.framework.dSYM/Contents/Resources/DWARF/App'), + exists); }, overrides: { FileSystem: () => fileSystem, @@ -625,17 +677,20 @@ void main() { fileSystem .file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') .createSync(recursive: true); - final File inputFramework = - fileSystem.file(fileSystem.path.join(environment.buildDir.path, 'App.framework', 'App')) - ..createSync(recursive: true) - ..writeAsStringSync('ABC'); - fileSystem.file(environment.buildDir.childFile('native_assets.json')).createSync(); + final File inputFramework = fileSystem.file(fileSystem.path + .join(environment.buildDir.path, 'App.framework', 'App')) + ..createSync(recursive: true) + ..writeAsStringSync('ABC'); + fileSystem + .file(environment.buildDir.childFile('native_assets.json')) + .createSync(); await const ProfileMacOSBundleFlutterAssets().build( environment..defines[kBuildMode] = 'profile', ); final File outputFramework = fileSystem.file( - fileSystem.path.join(environment.outputDir.path, 'App.framework', 'App'), + fileSystem.path + .join(environment.outputDir.path, 'App.framework', 'App'), ); expect(outputFramework.readAsStringSync(), 'ABC'); @@ -666,9 +721,12 @@ void main() { .file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') .createSync(recursive: true); fileSystem - .file(fileSystem.path.join(environment.buildDir.path, 'App.framework', 'App')) + .file(fileSystem.path + .join(environment.buildDir.path, 'App.framework', 'App')) .createSync(recursive: true); - fileSystem.file(environment.buildDir.childFile('native_assets.json')).createSync(); + fileSystem + .file(environment.buildDir.childFile('native_assets.json')) + .createSync(); await const ReleaseMacOSBundleFlutterAssets().build(environment); expect( @@ -702,7 +760,8 @@ void main() { expect( fakeAnalytics.sentEvents, contains( - Event.appleUsageEvent(workflow: 'assemble', parameter: 'macos-archive', result: 'fail'), + Event.appleUsageEvent( + workflow: 'assemble', parameter: 'macos-archive', result: 'fail'), ), ); }, @@ -739,7 +798,10 @@ void main() { '-install_name', '@rpath/App.framework/App', '-o', - environment.buildDir.childDirectory('App.framework').childFile('App').path, + environment.buildDir + .childDirectory('App.framework') + .childFile('App') + .path, ], ), ); @@ -753,6 +815,75 @@ void main() { }, ); + testUsingContext( + 'ReleaseMacOSBundleFlutterAssets updates shorebird.yaml if present', + () async { + environment.defines[kBuildMode] = 'release'; + environment.defines[kXcodeAction] = 'install'; + environment.defines[kFlavor] = 'internal'; + + // Set up engine artifacts + fileSystem + .file('bin/cache/artifacts/engine/darwin-x64/vm_isolate_snapshot.bin') + .createSync(recursive: true); + fileSystem + .file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') + .createSync(recursive: true); + + // Set up App.framework binary + fileSystem + .file(fileSystem.path + .join(environment.buildDir.path, 'App.framework', 'App')) + .createSync(recursive: true); + + // Set up native_assets.json (required by MacOSBundleFlutterAssets) + environment.buildDir.childFile('native_assets.json').createSync(); + + // Set up pubspec.yaml with shorebird.yaml as an asset + fileSystem.file('pubspec.yaml') + ..createSync() + ..writeAsStringSync(''' +name: example +flutter: + assets: + - shorebird.yaml +'''); + + // Create the shorebird.yaml asset file + fileSystem.file('shorebird.yaml') + ..createSync() + ..writeAsStringSync(''' +# Some other text that should be removed +app_id: base-app-id +flavors: + internal: internal-app-id + stable: stable-app-id +'''); + + // Set up package config + writePackageConfigFiles(directory: fileSystem.currentDirectory, mainLibName: 'example'); + + await const ReleaseMacOSBundleFlutterAssets().build(environment); + + // The output is in environment.outputDir, not buildDir + final String shorebirdYamlPath = fileSystem.path.join( + environment.outputDir.path, + 'App.framework', + 'Versions', + 'A', + 'Resources', + 'flutter_assets', + 'shorebird.yaml', + ); + expect(fileSystem.file(shorebirdYamlPath).readAsStringSync(), + 'app_id: internal-app-id'); + }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }, + ); + testUsingContext( 'DebugMacOSFramework creates universal binary', () async { @@ -782,7 +913,10 @@ void main() { '-install_name', '@rpath/App.framework/App', '-o', - environment.buildDir.childDirectory('App.framework').childFile('App').path, + environment.buildDir + .childDirectory('App.framework') + .childFile('App') + .path, ], ), ); @@ -810,11 +944,13 @@ void main() { .childFile('x86_64/App.framework.dSYM/Contents/Resources/DWARF/App') .createSync(recursive: true); + final build = environment.buildDir.path; processManager.addCommands([ FakeCommand( command: [ 'Artifact.genSnapshotArm64.TargetPlatform.darwin.release', '--deterministic', + ...linkInfoArgsFor(build), '--snapshot_kind=app-aot-assembly', '--assembly=${environment.buildDir.childFile('arm64/snapshot_assembly.S').path}', environment.buildDir.childFile('app.dill').path, @@ -824,6 +960,7 @@ void main() { command: [ 'Artifact.genSnapshotX64.TargetPlatform.darwin.release', '--deterministic', + ...linkInfoArgsFor(build), '--snapshot_kind=app-aot-assembly', '--assembly=${environment.buildDir.childFile('x86_64/snapshot_assembly.S').path}', environment.buildDir.childFile('app.dill').path, @@ -951,14 +1088,18 @@ void main() { command: [ 'lipo', environment.buildDir - .childFile('arm64/App.framework.dSYM/Contents/Resources/DWARF/App') + .childFile( + 'arm64/App.framework.dSYM/Contents/Resources/DWARF/App') .path, environment.buildDir - .childFile('x86_64/App.framework.dSYM/Contents/Resources/DWARF/App') + .childFile( + 'x86_64/App.framework.dSYM/Contents/Resources/DWARF/App') .path, '-create', '-output', - environment.buildDir.childFile('App.framework.dSYM/Contents/Resources/DWARF/App').path, + environment.buildDir + .childFile('App.framework.dSYM/Contents/Resources/DWARF/App') + .path, ], ), ]); diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index f4743bb66a3e4..eebe3fef1a98a 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -108,7 +108,8 @@ void main() { final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_artifact.', ); - final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync( + final Directory downloadDir = + fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_download.', ); final Cache cache = FakeSecondaryCache() @@ -131,7 +132,8 @@ void main() { final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_artifact.', ); - final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync( + final Directory downloadDir = + fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_download.', ); final Cache cache = FakeSecondaryCache() @@ -143,7 +145,8 @@ void main() { final artifact = FakeSimpleArtifact(cache); await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils()); - expect(logger.warningText, contains('No known version for the artifact name "fake"')); + expect(logger.warningText, + contains('No known version for the artifact name "fake"')); }); testWithoutContext( @@ -156,16 +159,20 @@ void main() { fileSystem.path.join('artifacts', 'gradle_wrapper'), ); fileSystem - .file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')) + .file(fileSystem.path.join( + directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')) .createSync(recursive: true); expect(gradleWrapper.isUpToDateInner(fileSystem), false); }, ); - testWithoutContext('Gradle wrapper will delete .properties/NOTICES if they exist', () async { + testWithoutContext( + 'Gradle wrapper will delete .properties/NOTICES if they exist', + () async { final FileSystem fileSystem = MemoryFileSystem.test(); - final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync( + final Directory artifactDir = + fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_artifact.', ); final cache = FakeSecondaryCache() @@ -180,12 +187,15 @@ void main() { ); final gradleWrapper = GradleWrapper(cache); final File propertiesFile = fileSystem.file( - fileSystem.path.join(artifactDir.path, 'gradle', 'wrapper', 'gradle-wrapper.properties'), + fileSystem.path.join( + artifactDir.path, 'gradle', 'wrapper', 'gradle-wrapper.properties'), )..createSync(recursive: true); - final File noticeFile = fileSystem.file(fileSystem.path.join(artifactDir.path, 'NOTICE')) + final File noticeFile = fileSystem + .file(fileSystem.path.join(artifactDir.path, 'NOTICE')) ..createSync(recursive: true); - await gradleWrapper.updateInner(FakeArtifactUpdater(), fileSystem, operatingSystemUtils); + await gradleWrapper.updateInner( + FakeArtifactUpdater(), fileSystem, operatingSystemUtils); expect(propertiesFile, isNot(exists)); expect(noticeFile, isNot(exists)); @@ -201,7 +211,8 @@ void main() { fileSystem.path.join('artifacts', 'gradle_wrapper'), ); fileSystem - .file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')) + .file(fileSystem.path.join( + directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')) .createSync(recursive: true); fileSystem .file(fileSystem.path.join(directory.path, 'gradlew')) @@ -214,9 +225,12 @@ void main() { }, ); - testWithoutContext('should not be up to date, if some cached artifact is not', () async { - final CachedArtifact artifact1 = FakeSecondaryCachedArtifact()..upToDate = true; - final CachedArtifact artifact2 = FakeSecondaryCachedArtifact()..upToDate = false; + testWithoutContext( + 'should not be up to date, if some cached artifact is not', () async { + final CachedArtifact artifact1 = FakeSecondaryCachedArtifact() + ..upToDate = true; + final CachedArtifact artifact2 = FakeSecondaryCachedArtifact() + ..upToDate = false; final FileSystem fileSystem = MemoryFileSystem.test(); final cache = Cache.test( @@ -252,7 +266,8 @@ void main() { processManager: FakeProcessManager.any(), ); - await cache.updateAll({DevelopmentArtifact.universal}); + await cache + .updateAll({DevelopmentArtifact.universal}); expect(artifact1.didUpdate, false); expect(artifact2.didUpdate, true); }); @@ -299,7 +314,8 @@ void main() { logger: logger, ); await expectLater( - () => cache.updateAll({DevelopmentArtifact.universal}), + () => cache + .updateAll({DevelopmentArtifact.universal}), throwsException, ); expect(artifact1.didUpdate, true); @@ -311,7 +327,9 @@ void main() { testWithoutContext('Invalid URI for FLUTTER_STORAGE_BASE_URL throws ToolExit', () async { final cache = Cache.test( platform: FakePlatform( - environment: {'FLUTTER_STORAGE_BASE_URL': ' http://foo'}, + environment: { + 'FLUTTER_STORAGE_BASE_URL': ' http://foo' + }, ), processManager: FakeProcessManager.any(), ); @@ -329,7 +347,8 @@ void main() { ); expect(cache.storageBaseUrl, baseUrl); - expect(logger.warningText, contains('Flutter assets will be downloaded from $baseUrl')); + expect(logger.warningText, + contains('Flutter assets will be downloaded from $baseUrl')); expect(logger.statusText, isEmpty); }); @@ -354,15 +373,18 @@ void main() { testWithoutContext('flattenNameSubdirs', () { expect( - flattenNameSubdirs(Uri.parse('http://flutter.dev/foo/bar'), MemoryFileSystem.test()), + flattenNameSubdirs( + Uri.parse('http://flutter.dev/foo/bar'), MemoryFileSystem.test()), 'flutter.dev/foo/bar', ); expect( - flattenNameSubdirs(Uri.parse('http://api.flutter.dev/foo/bar'), MemoryFileSystem.test()), + flattenNameSubdirs( + Uri.parse('http://api.flutter.dev/foo/bar'), MemoryFileSystem.test()), 'api.flutter.dev/foo/bar', ); expect( - flattenNameSubdirs(Uri.parse('https://www.flutter.dev'), MemoryFileSystem.test()), + flattenNameSubdirs( + Uri.parse('https://www.flutter.dev'), MemoryFileSystem.test()), 'www.flutter.dev', ); }); @@ -372,10 +394,12 @@ void main() { () async { final operatingSystemUtils = FakeOperatingSystemUtils(); final FileSystem fileSystem = MemoryFileSystem.test(); - final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync( + final Directory artifactDir = + fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_artifact.', ); - final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync( + final Directory downloadDir = + fileSystem.systemTempDirectory.createTempSync( 'flutter_cache_test_download.', ); final cache = FakeSecondaryCache() @@ -400,7 +424,10 @@ void main() { expect(dir, isNotNull); expect(dir.path, artifactDir.childDirectory('bin_dir').path); expect(operatingSystemUtils.chmods, >[ - ['/.tmp_rand0/flutter_cache_test_artifact.rand0/bin_dir', 'a+r,a+x'], + [ + '/.tmp_rand0/flutter_cache_test_artifact.rand0/bin_dir', + 'a+r,a+x' + ], ]); }, ); @@ -433,7 +460,8 @@ void main() { packageUrl = url; }; - await artifact.updateInner(artifactUpdater, fileSystem, operatingSystemUtils); + await artifact.updateInner( + artifactUpdater, fileSystem, operatingSystemUtils); expect(packageUrl, isNotNull); expect( packageUrl.toString(), @@ -483,8 +511,8 @@ void main() { platform: FakePlatform(operatingSystem: 'macos'), ); iosUsbArtifacts.location.createSync(); - final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot') - ..createSync(); + final File ideviceScreenshotFile = + iosUsbArtifacts.location.childFile('idevicescreenshot')..createSync(); iosUsbArtifacts.location.childFile('idevicesyslog').createSync(); expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true); @@ -504,7 +532,8 @@ void main() { platform: FakePlatform(operatingSystem: 'macos'), ); iosUsbArtifacts.location.createSync(); - final File iproxy = iosUsbArtifacts.location.childFile('iproxy')..createSync(); + final File iproxy = iosUsbArtifacts.location.childFile('iproxy') + ..createSync(); expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true); @@ -549,10 +578,13 @@ void main() { platform: FakePlatform(operatingSystem: 'macos'), ); - expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/'))); + expect( + iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/'))); }); - testWithoutContext('FlutterRunnerDebugSymbols downloads Flutter runner debug symbols', () async { + testWithoutContext( + 'FlutterRunnerDebugSymbols downloads Flutter runner debug symbols', + () async { final FileSystem fileSystem = MemoryFileSystem.test(); final Cache cache = FakeSecondaryCache() ..artifactDirectory = fileSystem.currentDirectory @@ -623,7 +655,8 @@ void main() { testWithoutContext('FontSubset artifacts on macos', () { fakeProcessManager.addCommands([ - const FakeCommand(command: ['which', 'sysctl'], stdout: '/sbin/sysctl'), + const FakeCommand( + command: ['which', 'sysctl'], stdout: '/sbin/sysctl'), const FakeCommand( command: ['sysctl', 'hw.optional.arm64'], stdout: 'hw.optional.arm64: 0', @@ -672,7 +705,8 @@ void main() { ]); }); - testWithoutContext('FontSubset artifacts for all platforms on arm64 hosts', () { + testWithoutContext('FontSubset artifacts for all platforms on arm64 hosts', + () { fakeProcessManager.addCommand(unameCommandForArm64); final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia')); @@ -732,11 +766,15 @@ void main() { expect( artifacts.getBinaryDirs(), - containsAll([contains(contains('profile')), contains(contains('release'))]), + containsAll([ + contains(contains('profile')), + contains(contains('release')) + ]), ); }); - testWithoutContext('Linux desktop artifacts ignore filtering when requested', () { + testWithoutContext('Linux desktop artifacts ignore filtering when requested', + () { fakeProcessManager.addCommand(unameCommandForX64); final Cache cache = createCache(FakePlatform()); @@ -747,7 +785,9 @@ void main() { expect(artifacts.getBinaryDirs(), isNotEmpty); }); - testWithoutContext('Linux desktop artifacts for x64 include profile and release artifacts', () { + testWithoutContext( + 'Linux desktop artifacts for x64 include profile and release artifacts', + () { fakeProcessManager.addCommand(unameCommandForX64); final Cache cache = createCache(FakePlatform()); @@ -755,12 +795,20 @@ void main() { expect(artifacts.getBinaryDirs(), >[ ['linux-x64', 'linux-x64-debug/linux-x64-flutter-gtk.zip'], - ['linux-x64-profile', 'linux-x64-profile/linux-x64-flutter-gtk.zip'], - ['linux-x64-release', 'linux-x64-release/linux-x64-flutter-gtk.zip'], + [ + 'linux-x64-profile', + 'linux-x64-profile/linux-x64-flutter-gtk.zip' + ], + [ + 'linux-x64-release', + 'linux-x64-release/linux-x64-flutter-gtk.zip' + ], ]); }); - testWithoutContext('Linux desktop artifacts for arm64 include profile and release artifacts', () { + testWithoutContext( + 'Linux desktop artifacts for arm64 include profile and release artifacts', + () { fakeProcessManager.addCommand(unameCommandForArm64); final Cache cache = createCache(FakePlatform()); @@ -768,8 +816,14 @@ void main() { expect(artifacts.getBinaryDirs(), >[ ['linux-arm64', 'linux-arm64-debug/linux-arm64-flutter-gtk.zip'], - ['linux-arm64-profile', 'linux-arm64-profile/linux-arm64-flutter-gtk.zip'], - ['linux-arm64-release', 'linux-arm64-release/linux-arm64-flutter-gtk.zip'], + [ + 'linux-arm64-profile', + 'linux-arm64-profile/linux-arm64-flutter-gtk.zip' + ], + [ + 'linux-arm64-release', + 'linux-arm64-release/linux-arm64-flutter-gtk.zip' + ], ]); }); @@ -799,7 +853,8 @@ void main() { expect(toolStampFile, isNot(exists)); }); - testWithoutContext('Cache does not attempt to delete already missing stamp files', () { + testWithoutContext( + 'Cache does not attempt to delete already missing stamp files', () { final FileSystem fileSystem = MemoryFileSystem.test(); final artifactSet = FakeIosUsbArtifacts(); final logger = BufferLogger.test(); @@ -824,7 +879,8 @@ void main() { expect(toolStampFile, isNot(exists)); }); - testWithoutContext('Cache catches file system exception from missing tool stamp file', () { + testWithoutContext( + 'Cache catches file system exception from missing tool stamp file', () { final FileSystem fileSystem = MemoryFileSystem.test(); final artifactSet = FakeIosUsbArtifacts(); final logger = BufferLogger.test(); @@ -851,7 +907,8 @@ void main() { final Directory internalDir = fileSystem.currentDirectory .childDirectory('bin') .childDirectory('internal'); - final File canvasKitVersionFile = internalDir.childFile('canvaskit.version'); + final File canvasKitVersionFile = + internalDir.childFile('canvaskit.version'); canvasKitVersionFile.createSync(recursive: true); canvasKitVersionFile.writeAsStringSync('abcdefg'); @@ -879,12 +936,13 @@ void main() { }; webCacheDirectory.childFile('bar').createSync(recursive: true); - await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils()); + await webSdk.updateInner( + artifactUpdater, fileSystem, FakeOperatingSystemUtils()); expect(messages, ['Downloading Web SDK...']); expect(downloads, [ - 'https://storage.googleapis.com/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk.zip', + 'https://download.shorebird.dev/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk.zip', ]); expect(locations, ['/bin/cache/flutter_web_sdk']); @@ -901,7 +959,8 @@ void main() { final Directory internalDir = fileSystem.currentDirectory .childDirectory('bin') .childDirectory('internal'); - final File canvasKitVersionFile = internalDir.childFile('canvaskit.version'); + final File canvasKitVersionFile = + internalDir.childFile('canvaskit.version'); canvasKitVersionFile.createSync(recursive: true); canvasKitVersionFile.writeAsStringSync('abcdefg'); @@ -935,7 +994,8 @@ void main() { }; webCacheDirectory.childFile('bar').createSync(recursive: true); - await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils()); + await webSdk.updateInner( + artifactUpdater, fileSystem, FakeOperatingSystemUtils()); expect(downloads, [ 'https://flutter.storage.com/override/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk.zip', @@ -970,9 +1030,11 @@ void main() { ); await expectLater( - () => webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils()), + () => webSdk.updateInner( + artifactUpdater, fileSystem, FakeOperatingSystemUtils()), throwsToolExit( - message: RegExp('Unable to delete file or directory at "/bin/cache/flutter_web_sdk"'), + message: RegExp( + 'Unable to delete file or directory at "/bin/cache/flutter_web_sdk"'), ), ); }); @@ -1005,7 +1067,7 @@ void main() { expect(messages, ['Downloading engine information...']); expect(downloads, [ - 'https://storage.googleapis.com/flutter_infra_release/flutter/hijklmnop/engine_stamp.json', + 'https://download.shorebird.dev/flutter_infra_release/flutter/hijklmnop/engine_stamp.json', ]); expect(locations, ['/bin/cache']); // file copy is done by the real uploader; not the fake. @@ -1018,7 +1080,8 @@ void main() { final fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); final cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem); final File canvasKitWasm = fileSystem.file( - fileSystem.path.join(cache.getRoot().path, 'canvaskit', 'canvaskit.wasm'), + fileSystem.path + .join(cache.getRoot().path, 'canvaskit', 'canvaskit.wasm'), ); canvasKitWasm.createSync(recursive: true); canvasKitWasm.writeAsStringSync('hello world'); @@ -1053,7 +1116,8 @@ void main() { expect(cache.getStampFor('foo'), null); file.createSync(); - exceptionHandler.addError(file, FileSystemOp.read, const FileSystemException()); + exceptionHandler.addError( + file, FileSystemOp.read, const FileSystemException()); expect(cache.getStampFor('foo'), null); }); @@ -1074,7 +1138,8 @@ void main() { expect(cache.getStampFor('foo'), 'ABC'); }); - testWithoutContext('PubDependencies needs to be updated if the package config' + testWithoutContext( + 'PubDependencies needs to be updated if the package config' ' file or the source directories are missing', () async { final logger = BufferLogger.test(); final fileSystem = MemoryFileSystem.test(); @@ -1085,7 +1150,8 @@ void main() { projectFactory: FakeFlutterProjectFactory(), ); - expect(await pubDependencies.isUpToDate(fileSystem), false); // no package config + expect(await pubDependencies.isUpToDate(fileSystem), + false); // no package config fileSystem.file('packages/flutter_tools/.dart_tool/package_config.json') ..createSync(recursive: true) @@ -1106,7 +1172,8 @@ void main() { } '''); - expect(await pubDependencies.isUpToDate(fileSystem), false); // dependencies are missing. + expect(await pubDependencies.isUpToDate(fileSystem), + false); // dependencies are missing. fileSystem .file('.pub-cache/hosted/pub.dartlang.org/example-7.0.0/pubspec.yaml') @@ -1137,7 +1204,8 @@ void main() { expect( pub.invocations.first, predicate( - (FakePubInvocation invocation) => invocation.outputMode == PubOutputMode.failuresOnly, + (FakePubInvocation invocation) => + invocation.outputMode == PubOutputMode.failuresOnly, 'Pub invoked with PubOutputMode.none', ), ); @@ -1165,7 +1233,9 @@ void main() { setUp(() { memoryFileSystem = MemoryFileSystem.test(); - cache = Cache.test(fileSystem: memoryFileSystem, processManager: FakeProcessManager.any()); + cache = Cache.test( + fileSystem: memoryFileSystem, + processManager: FakeProcessManager.any()); fakeAndroidSdk = FakeAndroidSdk(); }); @@ -1175,7 +1245,8 @@ void main() { java: FakeJava(), platform: FakePlatform(), ); - expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven); + expect( + mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven); }); testUsingContext( @@ -1191,10 +1262,13 @@ void main() { ); expect(await mavenArtifacts.isUpToDate(memoryFileSystem!), isFalse); - final Directory gradleWrapperDir = cache!.getArtifactDirectory('gradle_wrapper') + final Directory gradleWrapperDir = cache! + .getArtifactDirectory('gradle_wrapper') ..createSync(recursive: true); gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant'); - gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant'); + gradleWrapperDir + .childFile('gradlew.bat') + .writeAsStringSync('irrelevant'); await mavenArtifacts.update( FakeArtifactUpdater(), @@ -1283,7 +1357,8 @@ class FakeCachedArtifact extends EngineCachedArtifact { } class FakeSimpleArtifact extends CachedArtifact { - FakeSimpleArtifact(Cache cache) : super('fake', cache, DevelopmentArtifact.universal); + FakeSimpleArtifact(Cache cache) + : super('fake', cache, DevelopmentArtifact.universal); @override Future updateInner( @@ -1432,12 +1507,14 @@ class FakeArtifactUpdater extends Fake implements ArtifactUpdater { void Function(String, Uri, Directory)? onDownloadFile; @override - Future downloadZippedTarball(String message, Uri url, Directory location) async { + Future downloadZippedTarball( + String message, Uri url, Directory location) async { onDownloadZipTarball?.call(message, url, location); } @override - Future downloadZipArchive(String message, Uri url, Directory location) async { + Future downloadZipArchive( + String message, Uri url, Directory location) async { onDownloadZipArchive?.call(message, url, location); } diff --git a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart index 313de4c74b164..df9af9f2247f5 100644 --- a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart @@ -574,6 +574,33 @@ void main() { 'params': {'url': 'http://localhost:123/', 'launched': false}, }); }); + + test('app.warning', () async { + final adapter = FakeFlutterDebugAdapter( + fileSystem: MemoryFileSystem.test(style: fsStyle), + platform: platform, + ); + + // Start listening for the forwarded event (don't await it yet, it won't + // be triggered until the call below). + final Future> forwardedEvent = adapter.dapToClientMessages.firstWhere( + (Map data) => data['event'] == 'flutter.forwardedEvent', + ); + + // Simulate Flutter emitting an `app.warning` event. + adapter.simulateStdoutMessage({ + 'event': 'app.warning', + 'params': {'warning': 'This is a test warning'}, + }); + + // Expect the message to be forwarded to the DAP client as the body of + // the forwarded event. + final Map message = await forwardedEvent; + expect(message['body'], { + 'event': 'app.warning', + 'params': {'warning': 'This is a test warning'}, + }); + }); }); group('handles reverse requests', () { diff --git a/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart b/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart index 46a7bf93186d8..a8a14bbb870d5 100644 --- a/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart @@ -1791,6 +1791,8 @@ invalid JSON '--console', '--environment-variables', '{"OS_ACTIVITY_DT_MODE": "enable"}', + '--log-output', + '/.tmp_rand0/core_devices.rand0/launch_log.txt', bundleId, ], stdout: ''' @@ -1830,6 +1832,8 @@ Waiting for the application to terminate... '--console', '--environment-variables', '{"OS_ACTIVITY_DT_MODE": "enable"}', + '--log-output', + '/.tmp_rand0/core_devices.rand0/launch_log.txt', bundleId, '--arg1', '--arg2', @@ -1872,6 +1876,8 @@ Waiting for the application to terminate... '--console', '--environment-variables', '{"OS_ACTIVITY_DT_MODE": "enable"}', + '--log-output', + '/.tmp_rand0/core_devices.rand0/launch_log.txt', bundleId, ], stdout: ''' @@ -1939,6 +1945,8 @@ Waiting for the application to terminate... '--console', '--environment-variables', '{"OS_ACTIVITY_DT_MODE": "enable"}', + '--log-output', + '/.tmp_rand0/core_devices.rand0/launch_log.txt', bundleId, ], exitCode: 1, @@ -1961,6 +1969,54 @@ ERROR: The operation couldn?t be completed. (OSStatus error -10814.) (NSOSStatus expect(logger.errorText, isEmpty); expect(result, isFalse); }); + + testWithoutContext('Successful launch with output in log file', () async { + final Completer launchCompleter = Completer(); + fakeProcessManager.addCommand( + FakeCommand( + command: const [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + '--start-stopped', + '--console', + '--environment-variables', + '{"OS_ACTIVITY_DT_MODE": "enable"}', + '--log-output', + '/.tmp_rand0/core_devices.rand0/launch_log.txt', + bundleId, + ], + onRun: (command) { + fileSystem.file('/.tmp_rand0/core_devices.rand0/launch_log.txt') + ..createSync(recursive: true) + ..writeAsStringSync(''' +10:04:12 Acquired tunnel connection to device. +10:04:12 Enabling developer disk image services. +10:04:12 Acquired usage assertion. +Launched application with com.example.my_app bundle identifier. +Waiting for the application to terminate... +'''); + }, + completer: launchCompleter, + ), + ); + + final bool result = await deviceControl.launchAppAndStreamLogs( + deviceId: deviceId, + bundleId: bundleId, + coreDeviceLogForwarder: FakeIOSCoreDeviceLogForwarder(), + startStopped: true, + ); + launchCompleter.complete(); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(result, isTrue); + }); }); group('terminate app', () { diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 17c01753f9f74..816fe0a545214 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -1289,6 +1289,86 @@ void main() { }, ); + group('IOSDevice warnIfSlowWirelessDebugging', () { + testWithoutContext('prints warning for slow wireless debugging on iOS 26+', () async { + final logger = BufferLogger.test(); + final IOSDevice device = setUpIOSDevice( + sdkVersion: '26.0.0', + logger: logger, + interfaceType: DeviceConnectionInterface.wireless, + ); + expect(device.isWirelesslyConnected, isTrue); + + device.warnIfSlowWirelessDebugging(DebuggingOptions.enabled(BuildInfo.debug)); + + const warningMessage = + 'Wireless debugging on iOS 26 may be slower than expected. ' + 'For better performance, consider using a wired (USB) connection.'; + expect(logger.warningText, contains(warningMessage)); + + final event = json.decode(logger.eventText) as Map; + expect(event['name'], 'app.warning'); + final args = event['args'] as Map; + expect( + args, + equals({ + 'warningId': 'ios-wireless-slow', + 'warning': warningMessage, + 'category': 'ios-wireless-performance', + 'deviceId': '123', + 'deviceOsVersion': 26, + 'actionable': true, + }), + ); + }); + testWithoutContext( + 'does not print slow wireless debugging warning on iOS less than 26', + () async { + final logger = BufferLogger.test(); + final IOSDevice device = setUpIOSDevice( + sdkVersion: '25.0', + logger: logger, + interfaceType: DeviceConnectionInterface.wireless, + ); + + device.warnIfSlowWirelessDebugging(DebuggingOptions.enabled(BuildInfo.debug)); + + expect(logger.warningText, isEmpty); + expect(logger.eventText, isEmpty); + }, + ); + + testWithoutContext( + 'does not print slow wireless debugging warning for wired device', + () async { + final logger = BufferLogger.test(); + final IOSDevice device = setUpIOSDevice(sdkVersion: '26.0', logger: logger); + + device.warnIfSlowWirelessDebugging(DebuggingOptions.enabled(BuildInfo.debug)); + + expect(logger.warningText, isEmpty); + expect(logger.eventText, isEmpty); + }, + ); + + testWithoutContext( + 'does not print slow wireless debugging warning for release mode', + () async { + final logger = BufferLogger.test(); + final IOSDevice device = setUpIOSDevice( + sdkVersion: '26.0', + logger: logger, + interfaceType: DeviceConnectionInterface.wireless, + ); + + device.warnIfSlowWirelessDebugging(DebuggingOptions.disabled(BuildInfo.release)); + + expect(logger.warningText, isEmpty); + expect(logger.eventText, isEmpty); + }, + ); + }); + group('IOSDevice.startApp attaches in debug mode via device logging', () { late FakeMDnsVmServiceDiscovery mdnsDiscovery; setUp(() { diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index b1598f5372398..12a2aed2a5fa7 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -670,6 +670,56 @@ duplicate symbol '_$s29plugin_1_name23PluginNamePluginC9setDouble3key5valueySS_S Pub: ThrowingPub.new, }, ); + + testWithoutContext('parses file has been modified error', () async { + const buildCommands = ['xcrun', 'cc', 'blah']; + final buildResult = XcodeBuildResult( + success: false, + stdout: '', + xcodeBuildExecution: XcodeBuildExecution( + buildCommands: buildCommands, + appDirectory: '/blah/blah', + environmentType: EnvironmentType.physical, + buildSettings: buildSettings, + ), + xcResult: XCResult.test( + issues: [ + XCResultIssue.test( + message: + "File 'path/to/Flutter.framework/Headers/FlutterPlugin.h' has been modified since " + "the precompiled header 'path/to/Runner.build/Objects-normal/arm64/Runner-primary-Bridging-header.pch'" + ' was built: size changed (was 18306, now 16886)', + subType: 'Error', + ), + XCResultIssue.test( + message: + "File 'path/to/Flutter.framework/Headers/FlutterEngine.h' has been modified since " + "the precompiled header 'path/to/Runner.build/Objects-normal/arm64/Runner-primary-Bridging-header.pch'" + ' was built: size changed (was 18306, now 16886)', + subType: 'Error', + ), + ], + ), + ); + final fs = MemoryFileSystem.test(); + final project = FakeFlutterProject(fileSystem: fs, usesSwiftPackageManager: true); + project.ios.podfile.createSync(recursive: true); + await diagnoseXcodeBuildFailure( + buildResult, + logger: logger, + analytics: fakeAnalytics, + fileSystem: fs, + platform: FlutterDarwinPlatform.ios, + project: project, + ); + expect( + logger.errorText, + contains( + 'A precompiled file has been changed since last built. Please run "flutter clean" to ' + 'clear the cache.', + ), + ); + }); }); group('Upgrades project.pbxproj for old asset usage', () { diff --git a/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart index 236b90749ccf9..23cdffc77624e 100644 --- a/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart @@ -93,7 +93,7 @@ void main() { await fileSystem.file('/some/path/to/llvm-ar').create(); await fileSystem.file('/some/path/to/ld.lld').create(); - final CCompilerConfig result = await cCompilerConfigLinux(); + final CCompilerConfig result = (await cCompilerConfigLinux(throwIfNotFound: true))!; expect(result.compiler, Uri.file('/some/path/to/clang')); }, ); @@ -115,7 +115,7 @@ void main() { await fileSystem.file('/path/to/$execName').create(recursive: true); } - final CCompilerConfig result = await cCompilerConfigLinux(); + final CCompilerConfig result = (await cCompilerConfigLinux(throwIfNotFound: true))!; expect(result.linker, Uri.file('/path/to/ld')); expect(result.compiler, Uri.file('/path/to/clang')); expect(result.archiver, Uri.file('/path/to/ar')); @@ -123,7 +123,7 @@ void main() { ); testUsingContext( - 'cCompilerConfigLinux with missing binaries', + 'cCompilerConfigLinux with missing binaries when required', overrides: { ProcessManager: () => FakeProcessManager.list([ const FakeCommand(command: ['which', 'clang++'], stdout: '/a/path/to/clang++'), @@ -137,7 +137,25 @@ void main() { await fileSystem.file('/a/path/to/clang++').create(recursive: true); - expect(cCompilerConfigLinux(), throwsA(isA())); + expect(cCompilerConfigLinux(throwIfNotFound: true), throwsA(isA())); + }, + ); + + testUsingContext( + 'cCompilerConfigLinux with missing binaries when not required', + overrides: { + ProcessManager: () => FakeProcessManager.list([ + const FakeCommand(command: ['which', 'clang++'], stdout: '/a/path/to/clang++'), + ]), + FileSystem: () => fileSystem, + }, + () async { + if (!const LocalPlatform().isLinux) { + return; + } + + await fileSystem.file('/a/path/to/clang++').create(recursive: true); + expect(cCompilerConfigLinux(throwIfNotFound: false), completes); }, ); } diff --git a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart index 8fdd918507db9..63de0fc6a171f 100644 --- a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart @@ -6,6 +6,7 @@ import 'package:code_assets/code_assets.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -359,17 +360,17 @@ void main() { // randomization causing issues with what processes are invoked. // Exercise the parsing of the process output in this separate test. testUsingContext( - 'NativeAssetsBuildRunnerImpl.cCompilerConfig', + 'NativeAssetsBuildRunnerImpl.cCompilerConfig normal installation', overrides: { ProcessManager: () => FakeProcessManager.list([ - const FakeCommand( - command: ['xcrun', 'clang', '--version'], - stdout: ''' -Apple clang version 14.0.0 (clang-1400.0.29.202) -Target: arm64-apple-darwin22.6.0 -Thread model: posix -InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin''', - ), + for (final binary in ['clang', 'ar', 'ld']) + FakeCommand( + command: ['xcrun', '--find', binary], + stdout: + ''' +/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/$binary +''', // NOTE: explicitly test needing to trim new line + ), ]), }, () async { @@ -377,13 +378,67 @@ InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault return; } - final CCompilerConfig result = await cCompilerConfigMacOS(); + final CCompilerConfig result = (await cCompilerConfigMacOS(throwIfNotFound: true))!; expect( result.compiler, Uri.file( '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang', ), ); + expect( + result.archiver, + Uri.file( + '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar', + ), + ); + expect( + result.linker, + Uri.file( + '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld', + ), + ); + }, + ); + + testUsingContext( + 'missing xcode when required', + overrides: { + ProcessManager: () => FakeProcessManager.list([ + for (final binary in ['clang', 'ar', 'ld']) + FakeCommand( + command: ['xcrun', '--find', binary], + exitCode: 1, + stderr: 'not found', + ), + ]), + }, + () async { + if (!const LocalPlatform().isMacOS) { + return; + } + + await expectLater(cCompilerConfigMacOS(throwIfNotFound: true), throwsA(isA())); + }, + ); + + testUsingContext( + 'missing xcode when not required', + overrides: { + ProcessManager: () => FakeProcessManager.list([ + for (final binary in ['clang', 'ar', 'ld']) + FakeCommand( + command: ['xcrun', '--find', binary], + exitCode: 1, + stderr: 'not found', + ), + ]), + }, + () async { + if (!const LocalPlatform().isMacOS) { + return; + } + + expect(await cCompilerConfigMacOS(throwIfNotFound: false), isNull); }, ); } diff --git a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart index 745573bc80f7a..01102949cd020 100644 --- a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart @@ -9,12 +9,14 @@ import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/targets/native_assets.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/isolated/native_assets/dart_hook_result.dart'; import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/targets.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -234,4 +236,63 @@ void main() { ); }, ); + + testUsingContext( + 'unit tests does not require compiler toolchain', + overrides: { + ProcessManager: () { + const Platform platform = LocalPlatform(); + return FakeProcessManager.list([ + if (platform.isMacOS) + for (final binary in ['clang', 'ar', 'ld']) + FakeCommand( + command: ['xcrun', '--find', binary], + exitCode: 1, + stderr: 'not found', + ), + if (platform.isLinux) + const FakeCommand( + command: ['which', 'clang++'], + exitCode: 1, + stderr: 'not found', + ), + ]); + }, + }, + () async { + // This calls setCCompilerConfig() on a test target, which must not throw despite the + // toolchain not being available. + const Platform platform = LocalPlatform(); + if (!platform.isLinux && !platform.isMacOS) { + return false; + } + + final target = _SetCCompilerConfigTarget( + packagesWithNativeAssetsResult: ['bar'], + buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(), + ); + + await runFlutterSpecificHooks( + environmentDefines: {}, + targetPlatform: TargetPlatform.tester, + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: target, + ); + + expect(target.didSetCCompilerConfig, isTrue); + }, + ); +} + +class _SetCCompilerConfigTarget extends FakeFlutterNativeAssetsBuildRunner { + _SetCCompilerConfigTarget({super.buildResult, super.packagesWithNativeAssetsResult}); + + var didSetCCompilerConfig = false; + + @override + Future setCCompilerConfig(CodeAssetTarget target) async { + await target.setCCompilerConfig(); + didSetCCompilerConfig = true; + } } diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 14f15128cab46..f07a3450efd21 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -2170,7 +2170,7 @@ flutter: nativeAssetsYamlFile: 'foo.yaml', ); - final int? result = await residentRunner.run(); + final int result = await residentRunner.run(); expect(result, 0); expect(residentCompiler.recompileCalled, true); diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 8e1017a7a879a..5820bfa6eb996 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -144,6 +144,7 @@ name: my_app webDevFS.result = ConnectionResult(appConnection, debugConnection, debugConnection.vmService); debugConnection.uri = 'ws://127.0.0.1/abcd/'; debugConnection.devToolsUri = 'http://127.0.0.1/abcd/'; + debugConnection.dtdUri = 'ws://127.0.0.1/efgh/'; chromeConnection.tabs.add(chromeTab); } @@ -260,6 +261,7 @@ name: my_app expect(appConnection.ranMain, true); expect(logger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/')); expect(debugConnectionInfo.wsUri.toString(), 'ws://127.0.0.1/abcd/'); + expect(debugConnectionInfo.dtdUri.toString(), 'ws://127.0.0.1/efgh/'); }, overrides: { FileSystem: () => fileSystem, @@ -963,7 +965,7 @@ name: my_app expect(debugConnectionInfo, isNotNull); final OperationResult result = await residentWebRunner.restart(); - expect(logger.statusText, contains('Recompile complete. No client connected.')); + expect(logger.statusText, contains(kNoClientConnectedMessage)); expect(result.code, 0); }, overrides: { @@ -1166,7 +1168,7 @@ name: my_app expect(result.code, 0); expect(result.isOk, isTrue); - expect(logger.statusText, contains('Recompile complete. No client connected.')); + expect(logger.statusText, contains(kNoClientConnectedMessage)); }, overrides: { Analytics: () => fakeAnalytics, @@ -2029,6 +2031,9 @@ class FakeDebugConnection extends Fake implements DebugConnection { @override late String devToolsUri; + @override + late String dtdUri; + final completer = Completer(); var didClose = false; diff --git a/packages/flutter_tools/test/general.shard/run_hot_test.dart b/packages/flutter_tools/test/general.shard/run_hot_test.dart index b4f0d6fdf06ee..66f8e47084594 100644 --- a/packages/flutter_tools/test/general.shard/run_hot_test.dart +++ b/packages/flutter_tools/test/general.shard/run_hot_test.dart @@ -105,6 +105,46 @@ void main() { }, ); }); + + group('multiple target devices', () { + late List<_FakeHotCompatibleFlutterDevice> flutterDevices; + late MemoryFileSystem fileSystem; + + setUp(() { + flutterDevices = [ + _FakeHotCompatibleFlutterDevice(FakeDevice()), + _FakeHotCompatibleFlutterDevice(FakeDevice()), + ]; + fileSystem = MemoryFileSystem.test(); + }); + + testUsingContext( + 'regression test for https://github.com/flutter/flutter/issues/179857', + () async { + final runner = HotRunner( + flutterDevices, + target: 'main.dart', + debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), + analytics: _FakeAnalytics(), + ); + + await runner.run(); + await runner.cleanupAfterSignal(); + + // Providing multiple Flutter devices should result in the target platform being set to + // 'multiple', which we use to report analytics. + expect(runner.targetPlatformName, 'multiple'); + for (final flutterDevice in flutterDevices) { + expect(flutterDevice.wasExited, true); + expect((flutterDevice.device.dds as FakeDartDevelopmentService).wasShutdown, true); + } + }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: FakeProcessManager.empty, + }, + ); + }); } class _FakeAnalytics extends Fake implements Analytics { diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index 1d6be5a665e61..4efde5883fcda 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -23,6 +23,7 @@ import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/reporting/crash_reporting.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:test/fake.dart'; +import 'package:unified_analytics/testing.dart'; import 'package:unified_analytics/unified_analytics.dart'; import '../../src/common.dart'; @@ -289,6 +290,67 @@ void main() { }, ); + testUsingContext( + "doesn't send multiple events for additional asynchronous exceptions " + 'thrown during shutdown', + () async { + // Regression test for https://github.com/flutter/flutter/issues/178318. + final command = MultipleExceptionCrashingFlutterCommand(); + var exceptionCount = 0; + unawaited( + runZonedGuarded?>( + () { + unawaited( + runner.run( + ['crash'], + () => [command], + // This flutterVersion disables crash reporting. + flutterVersion: '[user-branch]/', + reportCrashes: true, + shutdownHooks: ShutdownHooks(), + ), + ); + return null; + }, + (Object error, StackTrace stack) { + // Keep track of the number of exceptions thrown to ensure that + // the count matches the number of exceptions we expect. + exceptionCount++; + }, + ), + ); + await command.doneThrowing; + + // This is the main check of this test. + // + // We are checking that, even though multiple asynchronous errors were + // thrown, only a single crash report is sent. This ensures that a + // single process crash can't result in multiple crash events. + + // This test only makes sense if we've thrown more than one exception. + expect(exceptionCount, greaterThan(1)); + expect(exceptionCount, command.exceptionCount); + + // Ensure only a single exception analytics event was sent. + final List exceptionEvents = fakeAnalytics.sentEvents + .where((e) => e.eventName == DashEvent.exception) + .toList(); + expect(exceptionEvents, hasLength(1)); + }, + overrides: { + Analytics: () => fakeAnalytics, + Platform: () => FakePlatform( + environment: {'FLUTTER_ANALYTICS_LOG_FILE': 'test', 'FLUTTER_ROOT': '/'}, + ), + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + CrashReporter: () => WaitingCrashReporter(Future.value()), + Artifacts: () => Artifacts.test(), + HttpClientFactory: () => + () => FakeHttpClient.any(), + }, + ); + testUsingContext( 'create local report', () async { @@ -819,6 +881,34 @@ class CrashingFlutterCommand extends FlutterCommand { } } +class MultipleExceptionCrashingFlutterCommand extends FlutterCommand { + final _completer = Completer(); + + @override + String get description => ''; + + @override + String get name => 'crash'; + + Future get doneThrowing => _completer.future; + + var exceptionCount = 0; + + @override + Future runCommand() async { + Timer.periodic(const Duration(milliseconds: 10), (timer) { + exceptionCount++; + if (exceptionCount < 5) { + throw Exception('ERROR: $exceptionCount'); + } + timer.cancel(); + _completer.complete(); + }); + + return FlutterCommandResult.success(); + } +} + class _GitNotFoundFlutterCommand extends FlutterCommand { @override String get description => ''; diff --git a/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart b/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart new file mode 100644 index 0000000000000..7e05fec171409 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart @@ -0,0 +1,104 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:flutter_tools/src/shorebird/shorebird_yaml.dart'; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; + +void main() { + group('ShorebirdYaml', () { + test('yaml ignores comments', () { + const String yamlContents = ''' +# This file is used to configure the Shorebird updater used by your app. +app_id: 6160a7d8-cc18-4928-1233-05b51c0bb02c + +# auto_update controls if Shorebird should automatically update in the background on launch. +auto_update: false +'''; + final YamlDocument input = loadYamlDocument(yamlContents); + final YamlMap yamlMap = input.contents as YamlMap; + final Map compiled = + compileShorebirdYaml(yamlMap, flavor: null, environment: {}); + expect(compiled, { + 'app_id': '6160a7d8-cc18-4928-1233-05b51c0bb02c', + 'auto_update': false, + }); + }); + test('flavors', () { + // These are invalid app_ids but make for easy testing. + const String yamlContents = ''' +app_id: 1-a +auto_update: false +flavors: + foo: 2-a + bar: 3-a +'''; + final YamlDocument input = loadYamlDocument(yamlContents); + final YamlMap yamlMap = input.contents as YamlMap; + expect(appIdForFlavor(yamlMap, flavor: null), '1-a'); + expect(appIdForFlavor(yamlMap, flavor: 'foo'), '2-a'); + expect(appIdForFlavor(yamlMap, flavor: 'bar'), '3-a'); + expect(() => appIdForFlavor(yamlMap, flavor: 'unknown'), throwsException); + }); + test('all values', () { + // These are invalid app_ids but make for easy testing. + const String yamlContents = ''' +app_id: 1-a +auto_update: false +flavors: + foo: 2-a + bar: 3-a +base_url: https://example.com +patch_verification: strict +'''; + final YamlDocument input = loadYamlDocument(yamlContents); + final YamlMap yamlMap = input.contents as YamlMap; + final Map compiled1 = + compileShorebirdYaml(yamlMap, flavor: null, environment: {}); + expect(compiled1, { + 'app_id': '1-a', + 'auto_update': false, + 'base_url': 'https://example.com', + 'patch_verification': 'strict', + }); + final Map compiled2 = + compileShorebirdYaml(yamlMap, flavor: 'foo', environment: {'SHOREBIRD_PUBLIC_KEY': '4-a'}); + expect(compiled2, { + 'app_id': '2-a', + 'auto_update': false, + 'base_url': 'https://example.com', + 'patch_verification': 'strict', + 'patch_public_key': '4-a', + }); + }); + test('edit in place', () { + const String yamlContents = ''' +app_id: 1-a +auto_update: false +flavors: + foo: 2-a + bar: 3-a +base_url: https://example.com +'''; + // Make a temporary file to test editing in place. + final Directory tempDir = Directory.systemTemp.createTempSync('shorebird_yaml_test.'); + final File tempFile = File('${tempDir.path}/shorebird.yaml'); + tempFile.writeAsStringSync(yamlContents); + updateShorebirdYaml( + 'foo', + tempFile.path, + environment: {'SHOREBIRD_PUBLIC_KEY': '4-a'}, + ); + final String updatedContents = tempFile.readAsStringSync(); + // Order is not guaranteed, so parse as YAML to compare. + final YamlDocument updated = loadYamlDocument(updatedContents); + final YamlMap yamlMap = updated.contents as YamlMap; + expect(yamlMap['app_id'], '2-a'); + expect(yamlMap['auto_update'], false); + expect(yamlMap['base_url'], 'https://example.com'); + }); + }); +} diff --git a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart index f2b052520f00a..c5ebefe471e5f 100644 --- a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart +++ b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart @@ -1405,20 +1405,20 @@ class TestRunner extends Fake implements ResidentRunner { } @override - Future run({ + Future run({ Completer? connectionInfoCompleter, Completer? appStartedCompleter, bool enableDevTools = false, String? route, - }) async => null; + }) async => -1; @override - Future attach({ + Future attach({ Completer? connectionInfoCompleter, Completer? appStartedCompleter, bool enableDevTools = false, bool needsFullRestart = true, - }) async => null; + }) async => -1; } class _TestSignals implements Signals { diff --git a/packages/flutter_tools/test/general.shard/utils_test.dart b/packages/flutter_tools/test/general.shard/utils_test.dart index e55c5898af23b..6122452b386e2 100644 --- a/packages/flutter_tools/test/general.shard/utils_test.dart +++ b/packages/flutter_tools/test/general.shard/utils_test.dart @@ -2,10 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; +import 'dart:convert'; + import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/base/version.dart'; +import 'package:stack_trace/stack_trace.dart'; import '../src/common.dart'; @@ -521,4 +525,47 @@ needs to be wrapped. '10.0MB', ); }); + + testWithoutContext('Stream.transformWithCallSite', () async { + final inputController = StreamController(); + const jsonMap = {'foo': 123}; + const invalidJson = 'Hello world!'; + + final validCompleter = Completer(); + final errorCompleter = Completer(); + + // Wrap the callsite of `transformWithCallSite` with a named function to be more confident + // that the top frame is the location we expect without actually needing to check exact line + // and column numbers. + void listenToStream() { + inputController.stream + .transformWithCallSite(json.decoder) + .listen( + (result) { + expect(validCompleter.isCompleted, false); + expect(result, jsonMap); + validCompleter.complete(); + }, + onError: (Object e, StackTrace st) { + expect(errorCompleter.isCompleted, false); + expect(e, isA()); + final trace = Trace.from(st); + // Validate that the top stack frame corresponds to where `transformWithCallSite` + // was invoked. + expect(trace.frames.first.member, 'main..listenToStream'); + errorCompleter.complete(); + }, + ); + } + + listenToStream(); + + // Write both valid and invalid JSON to the stream. + inputController.add(json.encode(jsonMap)); + inputController.add(invalidJson); + + await inputController.sink.close(); + await validCompleter.future; + await errorCompleter.future; + }); } diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index 3b08c90397644..adbaded9eb995 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -67,6 +67,20 @@ void main() { required int commitsBetweenRefs, }) { return [ + // Shorebird release branch check (returns empty to fall through to + // regular version lookup). + FakeCommand( + command: [ + 'git', + 'for-each-ref', + '--contains', + headRef, + '--format', + '%(refname:short)', + 'refs/remotes/origin/flutter_release/*', + ], + stdout: '', + ), FakeCommand( command: const [ 'git', diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart index 0226c1895c59d..8ddd80559f669 100644 --- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart @@ -53,6 +53,18 @@ const _vs2022Response = { 'catalog': {'productDisplayVersion': '17.0.0'}, }; +// A minimum version of a response where a VS 2026 installation was found. +const _vs2026Response = { + 'installationPath': visualStudioPath, + 'displayName': 'Visual Studio Community 2026', + 'installationVersion': '18.0.11116.177', + 'isRebootRequired': false, + 'isComplete': true, + 'isLaunchable': true, + 'isPrerelease': false, + 'catalog': {'productDisplayVersion': 'Insiders [11116.177]'}, +}; + // A minimum version of a response where a Build Tools installation was found. const _defaultBuildToolsResponse = { 'installationPath': visualStudioPath, @@ -829,6 +841,27 @@ void main() { expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); + testWithoutContext('properties return the right value for Visual Studio 2026', () { + final VisualStudioFixture fixture = setUpVisualStudio(); + final VisualStudio visualStudio = fixture.visualStudio; + + setMockCompatibleVisualStudioInstallation( + _vs2026Response, + fixture.fileSystem, + fixture.processManager, + ); + + expect(visualStudio.isInstalled, true); + expect(visualStudio.isAtLeastMinimumVersion, true); + expect(visualStudio.hasNecessaryComponents, true); + expect(visualStudio.cmakePath, equals(cmakePath)); + expect(visualStudio.cmakeGenerator, equals('Visual Studio 18 2026')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); + }); + testWithoutContext('Metadata is for compatible version when latest is missing components', () { final VisualStudioFixture fixture = setUpVisualStudio(); final VisualStudio visualStudio = fixture.visualStudio; diff --git a/packages/flutter_tools/test/integration.shard/hot_reload_websocket_test.dart b/packages/flutter_tools/test/integration.shard/hot_reload_websocket_test.dart index 91dcc0cf420df..046d1368e9fa1 100644 --- a/packages/flutter_tools/test/integration.shard/hot_reload_websocket_test.dart +++ b/packages/flutter_tools/test/integration.shard/hot_reload_websocket_test.dart @@ -8,7 +8,7 @@ library; import 'dart:async'; import 'package:file/file.dart'; - +import 'package:flutter_tools/src/isolated/resident_web_runner.dart' show kNoClientConnectedMessage; import '../src/common.dart'; import 'test_data/hot_reload_project.dart'; import 'test_data/websocket_dwds_test_common.dart'; @@ -54,7 +54,7 @@ void testAll({List additionalCommandArgs = const []}) { try { // Test hot reload functionality - debugPrint('Step 6: Testing hot reload with WebSocket connection...'); + debugPrint('Testing hot reload with WebSocket connection...'); await flutter.hotReload().timeout( hotReloadTimeout, onTimeout: () { @@ -80,5 +80,71 @@ void testAll({List additionalCommandArgs = const []}) { }, skip: !platform.isMacOS, // Skip on non-macOS platforms where Chrome paths may differ ); + + testWithoutContext( + 'hot reload gracefully handles closed browser (no clients available)', + () async { + debugPrint('Starting test for no clients available scenario...'); + + // Set up WebSocket connection + final WebSocketDwdsTestSetup setup = await WebSocketDwdsTestUtils.setupWebSocketConnection( + flutter, + additionalCommandArgs: additionalCommandArgs, + ); + + try { + // First, verify hot reload works with browser connected + debugPrint('Verifying initial hot reload with browser connected...'); + await flutter.hotReload().timeout( + hotReloadTimeout, + onTimeout: () { + throw Exception('Initial hot reload timed out'); + }, + ); + + await Future.delayed(const Duration(seconds: 1)); + final initialOutput = setup.stdout.toString(); + expect(initialOutput, contains('Reloaded'), reason: 'Initial hot reload should succeed'); + debugPrint('โœ“ Initial hot reload succeeded'); + + // Close the browser to simulate no clients available + debugPrint('Closing browser to simulate no clients available...'); + setup.chromeProcess.kill(); + await setup.chromeProcess.exitCode; + debugPrint('โœ“ Browser closed'); + + // Give DWDS time to detect the disconnection + await Future.delayed(const Duration(seconds: 2)); + + // Attempt hot reload with no browser connected + debugPrint('Attempting hot reload with no browser connected...'); + await flutter.hotReload().timeout( + hotReloadTimeout, + onTimeout: () { + throw Exception('Hot reload with no clients timed out'); + }, + ); + + // Give some time for logs to capture + await Future.delayed(const Duration(seconds: 2)); + + final output = setup.stdout.toString(); + + // Verify the graceful handling message + expect( + output, + contains(kNoClientConnectedMessage), + reason: 'Should show no client connected message', + ); + + debugPrint('โœ“ Hot reload handled no clients gracefully'); + debugPrint('โœ“ Test completed: Verified graceful handling when browser is closed'); + } finally { + // Note: Chrome process is already killed in the test, so just cancel subscription + await setup.subscription.cancel(); + } + }, + skip: !platform.isMacOS, // Skip on non-macOS platforms where Chrome paths may differ + ); }); } diff --git a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_test.dart b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_test.dart index b150ed68c2140..38fcc42d9caf4 100644 --- a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_test.dart +++ b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_test.dart @@ -97,7 +97,10 @@ void main() { '-d', device, '--$mode', - if (device == 'chrome') '--no-web-resources-cdn', + if (device == 'chrome') ...[ + '--no-web-resources-cdn', + '--web-browser-flag=--no-sandbox', + ], ], root.path, [ diff --git a/packages/flutter_tools/test/integration.shard/test_data/plugin_project.dart b/packages/flutter_tools/test/integration.shard/test_data/plugin_project.dart index aca73a220d0fd..ec41acfa41b63 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/plugin_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/plugin_project.dart @@ -16,13 +16,13 @@ class PluginDeferredComponentsConfig extends BasicDeferredComponentsConfig { @override String get androidBuild => r''' buildscript { - ext.kotlin_version = '2.1.0' + ext.kotlin_version = '2.2.20' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.1.0' + classpath 'com.android.tools.build:gradle:8.11.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } configurations.classpath { diff --git a/packages/flutter_tools/test/integration.shard/test_data/websocket_dwds_test_common.dart b/packages/flutter_tools/test/integration.shard/test_data/websocket_dwds_test_common.dart index aceb33b35b681..13827a1666c5b 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/websocket_dwds_test_common.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/websocket_dwds_test_common.dart @@ -51,7 +51,7 @@ class WebSocketDwdsTestUtils { required List additionalCommandArgs, WebSocketDwdsTestConfig config = const WebSocketDwdsTestConfig(), }) async { - debugPrint('Step 1: Starting WebSocket DWDS connection setup...'); + debugPrint('Starting WebSocket DWDS connection setup...'); // Set up listening for app output before starting final stdout = StringBuffer(); @@ -72,15 +72,15 @@ class WebSocketDwdsTestUtils { io.Process? chromeProcess; try { - // Step 1: Start Flutter app with web-server device (will wait for debug connection) - debugPrint('Step 2: Starting Flutter app with web-server device...'); + // Start Flutter app with web-server device (will wait for debug connection) + debugPrint('Starting Flutter app with web-server device...'); final Future appStartFuture = runFlutterWithWebServerDevice( flutter, additionalCommandArgs: [...additionalCommandArgs, '--no-web-resources-cdn'], ); - // Step 2: Wait for DWDS debug URL to be available - debugPrint('Step 3: Waiting for DWDS debug service URL...'); + // Wait for DWDS debug URL to be available + debugPrint('Waiting for DWDS debug service URL...'); final String debugUrl = await sawDebugUrl.future.timeout( config.debugUrlTimeout, onTimeout: () { @@ -89,13 +89,13 @@ class WebSocketDwdsTestUtils { ); debugPrint('โœ“ DWDS debug service available at: $debugUrl'); - // Step 3: Launch headless Chrome to connect to DWDS - debugPrint('Step 4: Launching headless Chrome to connect to DWDS...'); + // Launch headless Chrome to connect to DWDS + debugPrint('Launching headless Chrome to connect to DWDS...'); chromeProcess = await launchHeadlessChrome(debugUrl); debugPrint('โœ“ Headless Chrome launched and connecting to DWDS'); - // Step 4: Wait for app to start (Chrome connection established) - debugPrint('Step 5: Waiting for Flutter app to start after Chrome connection...'); + // Wait for app to start (Chrome connection established) + debugPrint('Waiting for Flutter app to start after Chrome connection...'); await appStartFuture.timeout( config.appStartTimeout, onTimeout: () { diff --git a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart index ef75a4da21ef2..98f0be0ad60da 100644 --- a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart +++ b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'package:dtd/dtd.dart'; import 'package:file/file.dart'; +import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/commands/widget_preview.dart'; @@ -116,6 +117,10 @@ void main() { await completer.future; } + void runFlutterClean() { + processManager.runSync([flutterBin, 'clean'], workingDirectory: tempDir.path); + } + group('flutter widget-preview start', () { testWithoutContext('smoke test', () async { await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb); @@ -125,13 +130,53 @@ void main() { await runWidgetPreview(expectedMessages: firstLaunchMessagesWebServer, useWebServer: true); }); - testWithoutContext('does not recreate project on subsequent runs', () async { - // The first run of 'flutter widget-preview start' should generate a new preview scaffold - await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb); + testWithoutContext( + 'does not recreate project on subsequent runs', + () async { + // The first run of 'flutter widget-preview start' should generate a new preview scaffold + await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb); - // We shouldn't regenerate the scaffold after the initial run. - await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb); - }); + // We shouldn't regenerate the scaffold after the initial run. + await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb); + }, + // Project is always regenerated. + skip: true, // See https://github.com/flutter/flutter/issues/179036. + ); + + testWithoutContext( + 'runs flutter pub get in widget_preview_scaffold if ' + "widget_preview_scaffold/.dart_tool doesn't exist", + () async { + // Regression test for https://github.com/flutter/flutter/issues/178660 + // Generate the widget preview scaffold, but don't bother launching it. + processManager.runSync([ + flutterBin, + 'widget-preview', + 'start', + '--no-${WidgetPreviewStartCommand.kLaunchPreviewer}', + ], workingDirectory: tempDir.path); + + // Ensure widget_preview_scaffold/.dart_tool/package_config.json exists. + final Directory widgetPreviewScaffoldDartTool = tempDir + .childDirectory('.dart_tool') + .childDirectory('widget_preview_scaffold') + .childDirectory('.dart_tool'); + expect(widgetPreviewScaffoldDartTool, exists); + expect(widgetPreviewScaffoldDartTool.childFile('package_config.json'), exists); + + // Delete widget_preview_scaffold/.dart_tool/. This simulates an interrupted + // flutter widget-preview start where 'flutter pub get' wasn't run after + // the widget_preview_scaffold project was created. + widgetPreviewScaffoldDartTool.deleteSync(recursive: true); + + // Ensure we don't crash due to the package_config.json lookup pointing to + // the parent project's package_config.json due to + // widget_preview_scaffold/.dart_tool/package_config.json not existing. + await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb); + }, + // Project is currently under $TMP. + skip: true, // See https://github.com/flutter/flutter/issues/179036. + ); testUsingContext('can connect to an existing DTD instance', () async { dtdLauncher = DtdLauncher( @@ -181,5 +226,48 @@ void main() { devToolsServerAddress: devtoolsUri, ); }); + + testUsingContext("doesn't crash on flutter clean", () async { + // Regression test for https://github.com/flutter/flutter/issues/175058.\ + dtdLauncher = DtdLauncher( + logger: logger!, + artifacts: globals.artifacts!, + processManager: globals.processManager, + ); + + // Start a DTD instance. + final Uri dtdUri = await dtdLauncher!.launch(); + + // Connect to it and listen to the WidgetPreviewScaffold stream. + // + // The preview scaffold will send a 'Connected' event on this stream once it has initialized + // and is ready. + final DartToolingDaemon dtdConnection = await DartToolingDaemon.connect(dtdUri); + const kWidgetPreviewScaffoldStream = 'WidgetPreviewScaffold'; + final completer = Completer(); + var firstConnection = true; + dtdConnection.onEvent(kWidgetPreviewScaffoldStream).listen((DTDEvent event) { + expect(event.stream, kWidgetPreviewScaffoldStream); + expect(event.kind, 'Connected'); + if (firstConnection) { + firstConnection = false; + runFlutterClean(); + dtdConnection.call( + WidgetPreviewDtdServices.kWidgetPreviewService, + WidgetPreviewDtdServices.kHotRestartPreviewer, + ); + return; + } + // The second `Connected` event should come after the previewer is hot restarted after + // we perform the `flutter clean`. This event won't be sent again if the previewer has + // crashed. + completer.complete(); + }); + await dtdConnection.streamListen(kWidgetPreviewScaffoldStream); + + // Start the widget preview and wait for the 'Connected' event. + await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb, dtdUri: dtdUri); + await completer.future; + }); }); } diff --git a/packages/flutter_tools/test/web.shard/chrome_test.dart b/packages/flutter_tools/test/web.shard/chrome_test.dart index 38760e9f195b0..64072828aad2c 100644 --- a/packages/flutter_tools/test/web.shard/chrome_test.dart +++ b/packages/flutter_tools/test/web.shard/chrome_test.dart @@ -30,7 +30,6 @@ const kChromeArgs = [ '--disable-default-apps', '--disable-translate', '--disable-search-engine-choice-screen', - '--no-sandbox', ]; const kCodeCache = ['Cache', 'Code Cache', 'GPUCache']; @@ -536,6 +535,7 @@ void main() { '--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0', '--remote-debugging-port=12345', ...kChromeArgs, + '--no-sandbox', '--headless', '--disable-gpu', '--window-size=2400,1800', @@ -621,6 +621,7 @@ void main() { '--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0', '--remote-debugging-port=12345', ...kChromeArgs, + '--no-sandbox', '--headless', '--disable-gpu', '--window-size=2400,1800', @@ -654,6 +655,7 @@ void main() { '--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0', '--remote-debugging-port=12345', ...kChromeArgs, + '--no-sandbox', '--headless', '--disable-gpu', '--window-size=2400,1800', @@ -691,6 +693,7 @@ void main() { '--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0', '--remote-debugging-port=12345', ...kChromeArgs, + '--no-sandbox', '--headless', '--disable-gpu', '--window-size=2400,1800', diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart new file mode 100644 index 0000000000000..092d71d51a484 --- /dev/null +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart @@ -0,0 +1,5 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const String kWidgetPreviewDtdUri = ''; diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_services.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_services.dart index ed5352dbd4181..d978222b03e70 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_services.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_services.dart @@ -6,14 +6,12 @@ import 'dart:async'; import 'package:dtd/dtd.dart'; import 'package:json_rpc_2/json_rpc_2.dart'; +import 'package:widget_preview_scaffold/src/dtd/dtd_connection_info.dart'; +import 'package:widget_preview_scaffold/src/dtd/editor_service.dart'; import 'package:widget_preview_scaffold/src/dtd/utils.dart'; -import 'editor_service.dart'; /// Provides services, streams, and RPC invocations to interact with Flutter developer tooling. class WidgetPreviewScaffoldDtdServices with DtdEditorService { - /// Environment variable for the DTD URI. - static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI'; - // WARNING: Keep these constants and services in sync with those defined in the widget preview // scaffold's dtd_services.dart. // @@ -37,9 +35,7 @@ class WidgetPreviewScaffoldDtdServices with DtdEditorService { /// If the connection is successful, the Widget Preview Scaffold will register services and /// subscribe to various streams to interact directly with other tooling (e.g., IDEs). Future connect({Uri? dtdUri}) async { - final Uri dtdWsUri = - dtdUri ?? - Uri.parse(const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar)); + final Uri dtdWsUri = dtdUri ?? Uri.parse(kWidgetPreviewDtdUri); dtd = await DartToolingDaemon.connect(dtdWsUri); unawaited( dtd.postEvent( diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart index 2c560d2892db3..c3e01b0812c67 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart @@ -14,16 +14,16 @@ import 'package:flutter/widget_previews.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'dtd/editor_service.dart'; -import 'theme/ide_theme.dart'; -import 'theme/theme.dart'; - -import 'controls.dart'; -import 'generated_preview.dart'; -import 'utils.dart'; -import 'widget_preview.dart'; -import 'widget_preview_inspector_service.dart'; -import 'widget_preview_scaffold_controller.dart'; +import 'package:widget_preview_scaffold/src/dtd/editor_service.dart'; +import 'package:widget_preview_scaffold/src/theme/ide_theme.dart'; +import 'package:widget_preview_scaffold/src/theme/theme.dart'; + +import 'package:widget_preview_scaffold/src/controls.dart'; +import 'package:widget_preview_scaffold/src/generated_preview.dart'; +import 'package:widget_preview_scaffold/src/utils.dart'; +import 'package:widget_preview_scaffold/src/widget_preview.dart'; +import 'package:widget_preview_scaffold/src/widget_preview_inspector_service.dart'; +import 'package:widget_preview_scaffold/src/widget_preview_scaffold_controller.dart'; /// Displayed when an unhandled exception is thrown when initializing the widget /// tree for a preview (i.e., before the build phase). diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/dtd_services_test.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/dtd_services_test.dart index 120cc064d1472..f5db35c3d95fd 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/dtd_services_test.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/dtd_services_test.dart @@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/widget_preview/analytics.dart'; import 'package:flutter_tools/src/widget_preview/dtd_services.dart'; import 'package:flutter_tools/src/widget_preview/persistent_preferences.dart'; import 'package:test/fake.dart'; @@ -18,7 +19,7 @@ import 'package:widget_preview_scaffold/src/dtd/dtd_services.dart'; import '../../../src/common.dart'; import '../../../src/context.dart'; -import '../../../src/test_flutter_command_runner.dart'; +import '../../../src/fakes.dart'; import '../../../commands.shard/permeable/utils/project_testing_utils.dart'; class FakeFlutterProject extends Fake implements FlutterProject { @@ -47,6 +48,14 @@ void main() { // restart requests. final hotRestartRequestCompleter = Completer(); dtdServer = WidgetPreviewDtdServices( + previewAnalytics: WidgetPreviewAnalytics( + analytics: getInitializedFakeAnalyticsInstance( + // We don't care about anything written to the file system by analytics, so we're safe + // to use a different file system here. + fs: MemoryFileSystem.test(), + fakeFlutterVersion: FakeFlutterVersion(), + ), + ), fs: MemoryFileSystem.test(), logger: logger, shutdownHooks: ShutdownHooks(), @@ -76,6 +85,14 @@ void main() { 'can set and retreive values from $PersistentPreferences', () async { dtdServer = WidgetPreviewDtdServices( + previewAnalytics: WidgetPreviewAnalytics( + analytics: getInitializedFakeAnalyticsInstance( + // We don't care about anything written to the file system by analytics, so we're safe + // to use a different file system here. + fs: MemoryFileSystem.test(), + fakeFlutterVersion: FakeFlutterVersion(), + ), + ), fs: MemoryFileSystem.test(), logger: logger, shutdownHooks: ShutdownHooks(), diff --git a/packages/shorebird_tests/.gitignore b/packages/shorebird_tests/.gitignore new file mode 100644 index 0000000000000..3a85790408401 --- /dev/null +++ b/packages/shorebird_tests/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/packages/shorebird_tests/README.md b/packages/shorebird_tests/README.md new file mode 100644 index 0000000000000..b87fb24a480da --- /dev/null +++ b/packages/shorebird_tests/README.md @@ -0,0 +1,2 @@ +A dart project that includes tests that perform asserts in the modifications +made on the Flutter framework by the Shorebird team. diff --git a/packages/shorebird_tests/analysis_options.yaml b/packages/shorebird_tests/analysis_options.yaml new file mode 100644 index 0000000000000..a767d79d7f4b1 --- /dev/null +++ b/packages/shorebird_tests/analysis_options.yaml @@ -0,0 +1,2 @@ +# This file configures the static analysis results for your project (errors, +include: package:lints/recommended.yaml diff --git a/packages/shorebird_tests/pubspec.yaml b/packages/shorebird_tests/pubspec.yaml new file mode 100644 index 0000000000000..d0fba0c1fa95d --- /dev/null +++ b/packages/shorebird_tests/pubspec.yaml @@ -0,0 +1,16 @@ +name: shorebird_tests +description: Shorebird's Flutter customizations tests +version: 1.0.0 + +environment: + sdk: ^3.3.4 + +dependencies: + archive: ^3.5.1 + path: ^1.9.0 + yaml: ^3.1.2 + +dev_dependencies: + lints: ^3.0.0 + meta: ^1.15.0 + test: ^1.24.0 diff --git a/packages/shorebird_tests/test/android_test.dart b/packages/shorebird_tests/test/android_test.dart new file mode 100644 index 0000000000000..b24cce0ee9bf6 --- /dev/null +++ b/packages/shorebird_tests/test/android_test.dart @@ -0,0 +1,92 @@ +import 'package:test/test.dart'; + +import 'shorebird_tests.dart'; + +void main() { + group('shorebird android projects', () { + testWithShorebirdProject('can build an apk', (projectDirectory) async { + await projectDirectory.runFlutterBuildApk(); + + expect(projectDirectory.apkFile().existsSync(), isTrue); + expect(projectDirectory.shorebirdFile.existsSync(), isTrue); + expect(projectDirectory.getGeneratedAndroidShorebirdYaml(), completes); + }); + + group('when passing the public key through the environment variable', () { + testWithShorebirdProject( + 'adds the public key on top of the original file', + (projectDirectory) async { + final originalYaml = projectDirectory.shorebirdYaml; + + const base64PublicKey = 'public_123'; + await projectDirectory.runFlutterBuildApk( + environment: { + 'SHOREBIRD_PUBLIC_KEY': base64PublicKey, + }, + ); + + final generatedYaml = + await projectDirectory.getGeneratedAndroidShorebirdYaml(); + + expect( + generatedYaml.keys, + containsAll(originalYaml.keys), + ); + + expect( + generatedYaml['patch_public_key'], + equals(base64PublicKey), + ); + }, + ); + }); + + group('when building with a flavor', () { + testWithShorebirdProject( + 'correctly changes the app id', + (projectDirectory) async { + await projectDirectory.addProjectFlavors(); + projectDirectory.addShorebirdFlavors(); + + await projectDirectory.runFlutterBuildApk(flavor: 'internal'); + + final generatedYaml = + await projectDirectory.getGeneratedAndroidShorebirdYaml( + flavor: 'internal', + ); + + expect(generatedYaml['app_id'], equals('internal_123')); + }, + ); + + group('when public key passed through environment variable', () { + testWithShorebirdProject( + 'correctly changes the app id and adds the public key', + (projectDirectory) async { + const base64PublicKey = 'public_123'; + await projectDirectory.addProjectFlavors(); + projectDirectory.addShorebirdFlavors(); + + await projectDirectory.runFlutterBuildApk( + flavor: 'internal', + environment: { + 'SHOREBIRD_PUBLIC_KEY': base64PublicKey, + }, + ); + + final generatedYaml = + await projectDirectory.getGeneratedAndroidShorebirdYaml( + flavor: 'internal', + ); + + expect(generatedYaml['app_id'], equals('internal_123')); + expect( + generatedYaml['patch_public_key'], + equals(base64PublicKey), + ); + }, + ); + }); + }); + }); +} diff --git a/packages/shorebird_tests/test/base_test.dart b/packages/shorebird_tests/test/base_test.dart new file mode 100644 index 0000000000000..14dba7ca6cc85 --- /dev/null +++ b/packages/shorebird_tests/test/base_test.dart @@ -0,0 +1,15 @@ +import 'package:test/test.dart'; + +import 'shorebird_tests.dart'; + +void main() { + group('shorebird helpers', () { + testWithShorebirdProject('can build a base project', + (projectDirectory) async { + expect(projectDirectory.existsSync(), isTrue); + + expect(projectDirectory.pubspecFile.existsSync(), isTrue); + expect(projectDirectory.shorebirdFile.existsSync(), isTrue); + }); + }); +} diff --git a/packages/shorebird_tests/test/ios_test.dart b/packages/shorebird_tests/test/ios_test.dart new file mode 100644 index 0000000000000..3fe6e1652c3e5 --- /dev/null +++ b/packages/shorebird_tests/test/ios_test.dart @@ -0,0 +1,91 @@ +import 'package:test/test.dart'; + +import 'shorebird_tests.dart'; + +void main() { + group( + 'shorebird ios projects', + () { + testWithShorebirdProject('can build', (projectDirectory) async { + await projectDirectory.runFlutterBuildIos(); + + expect(projectDirectory.iosArchiveFile().existsSync(), isTrue); + expect(projectDirectory.getGeneratedIosShorebirdYaml(), completes); + }); + + group('when passing the public key through the environment variable', () { + testWithShorebirdProject( + 'adds the public key on top of the original file', + (projectDirectory) async { + final originalYaml = projectDirectory.shorebirdYaml; + + const base64PublicKey = 'public_123'; + await projectDirectory.runFlutterBuildIos( + environment: { + 'SHOREBIRD_PUBLIC_KEY': base64PublicKey, + }, + ); + + final generatedYaml = + await projectDirectory.getGeneratedIosShorebirdYaml(); + + expect( + generatedYaml.keys, + containsAll(originalYaml.keys), + ); + + expect( + generatedYaml['patch_public_key'], + equals(base64PublicKey), + ); + }, + ); + }); + + group('when building with a flavor', () { + testWithShorebirdProject( + 'correctly changes the app id', + (projectDirectory) async { + await projectDirectory.addProjectFlavors(); + projectDirectory.addShorebirdFlavors(); + + await projectDirectory.runFlutterBuildIos(flavor: 'internal'); + + final generatedYaml = + await projectDirectory.getGeneratedIosShorebirdYaml(); + + expect(generatedYaml['app_id'], equals('internal_123')); + }, + ); + + group('when public key passed through environment variable', () { + testWithShorebirdProject( + 'correctly changes the app id and adds the public key', + (projectDirectory) async { + const base64PublicKey = 'public_123'; + await projectDirectory.addProjectFlavors(); + projectDirectory.addShorebirdFlavors(); + + await projectDirectory.runFlutterBuildIos( + flavor: 'internal', + environment: { + 'SHOREBIRD_PUBLIC_KEY': base64PublicKey, + }, + ); + + final generatedYaml = + await projectDirectory.getGeneratedIosShorebirdYaml(); + + expect(generatedYaml['app_id'], equals('internal_123')); + expect( + generatedYaml['patch_public_key'], + equals(base64PublicKey), + ); + }, + ); + }); + }); + }, + testOn: 'mac-os', + ); +} diff --git a/packages/shorebird_tests/test/shorebird_tests.dart b/packages/shorebird_tests/test/shorebird_tests.dart new file mode 100644 index 0000000000000..6c08685ad29ef --- /dev/null +++ b/packages/shorebird_tests/test/shorebird_tests.dart @@ -0,0 +1,336 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:archive/archive_io.dart'; +import 'package:path/path.dart' as path; + +import 'package:meta/meta.dart'; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; + +/// This will be the path to the flutter binary housed in this flutter repository. +/// +/// Which since we are running the tests from this inner package , we need to go up two directories +/// in order to find the flutter binary in the bin folder. +File get _flutterBinaryFile => File( + path.join( + Directory.current.path, + '..', + '..', + 'bin', + 'flutter${Platform.isWindows ? '.bat' : ''}', + ), + ); + +/// Whether to print line-by-line subprocess output. +/// +/// Set the `VERBOSE` environment variable to enable streaming output, +/// which is useful for debugging timeouts in CI. +final bool _verbose = Platform.environment.containsKey('VERBOSE'); + +/// Runs a flutter command using the correct binary ([_flutterBinaryFile]) with the given arguments. +/// +/// Streams stdout and stderr to the test output in real time when [_verbose] +/// is true, so CI logs show progress even if the process hangs or times out. +Future _runFlutterCommand( + List arguments, { + required Directory workingDirectory, + Map? environment, +}) async { + final String command = 'flutter ${arguments.join(' ')}'; + print('[$command] starting...'); + final stopwatch = Stopwatch()..start(); + + final Process process = await Process.start( + _flutterBinaryFile.absolute.path, + arguments, + workingDirectory: workingDirectory.path, + environment: { + 'FLUTTER_STORAGE_BASE_URL': 'https://download.shorebird.dev', + if (environment != null) ...environment, + }, + ); + + final StringBuffer stdoutBuffer = StringBuffer(); + final StringBuffer stderrBuffer = StringBuffer(); + + process.stdout.transform(utf8.decoder).listen((String data) { + stdoutBuffer.write(data); + if (_verbose) { + for (final String line in data.split('\n')) { + if (line.isNotEmpty) { + print(' [$command] $line'); + } + } + } + }); + + process.stderr.transform(utf8.decoder).listen((String data) { + stderrBuffer.write(data); + if (_verbose) { + for (final String line in data.split('\n')) { + if (line.isNotEmpty) { + print(' [$command] (stderr) $line'); + } + } + } + }); + + final int exitCode = await process.exitCode; + stopwatch.stop(); + print('[$command] completed in ${stopwatch.elapsed} ' + '(exit code $exitCode)'); + if (exitCode != 0 && !_verbose) { + print('[$command] stdout:\n$stdoutBuffer'); + print('[$command] stderr:\n$stderrBuffer'); + } + + return ProcessResult( + process.pid, + exitCode, + stdoutBuffer.toString(), + stderrBuffer.toString(), + ); +} + +Future _createFlutterProject(Directory projectDirectory) async { + final result = await _runFlutterCommand( + ['create', '--empty', '.'], + workingDirectory: projectDirectory, + ); + if (result.exitCode != 0) { + throw Exception('Failed to create Flutter project: ${result.stderr}'); + } +} + +@isTest +Future testWithShorebirdProject(String name, + FutureOr Function(Directory projectDirectory) testFn) async { + test( + name, + () async { + final parentDirectory = Directory.systemTemp.createTempSync(); + final projectDirectory = Directory( + path.join( + parentDirectory.path, + 'shorebird_test', + ), + )..createSync(); + + try { + await _createFlutterProject(projectDirectory); + + projectDirectory.pubspecFile.writeAsStringSync(''' +${projectDirectory.pubspecFile.readAsStringSync()} + assets: + - shorebird.yaml +'''); + + File( + path.join( + projectDirectory.path, + 'shorebird.yaml', + ), + ).writeAsStringSync(''' +app_id: "123" +'''); + + await testFn(projectDirectory); + } finally { + projectDirectory.deleteSync(recursive: true); + } + }, + timeout: Timeout( + // These tests usually run flutter create, flutter build, etc, which can take a while, + // specially in CI, so setting from the default of 30 seconds to 6 minutes. + Duration(minutes: 6), + ), + ); +} + +extension ShorebirdProjectDirectoryOnDirectory on Directory { + File get pubspecFile => File( + path.join(this.path, 'pubspec.yaml'), + ); + + File get shorebirdFile => File( + path.join(this.path, 'shorebird.yaml'), + ); + + YamlMap get shorebirdYaml => + loadYaml(shorebirdFile.readAsStringSync()) as YamlMap; + + File get appGradleFile => File( + path.join(this.path, 'android', 'app', 'build.gradle'), + ); + + Future addPubDependency(String name, {bool dev = false}) async { + final result = await _runFlutterCommand( + ['pub', 'add', if (dev) '--dev', name], + workingDirectory: this, + ); + if (result.exitCode != 0) { + throw Exception( + 'Failed to run `flutter pub add $name`: ${result.stderr}'); + } + } + + Future addProjectFlavors() async { + await addPubDependency( + // TODO(felangel): revert to using published version once 3.29.0 support is released. + // https://github.com/AngeloAvv/flutter_flavorizr/pull/291 + 'dev:flutter_flavorizr:{"git":{"url":"https://github.com/wjlee611/flutter_flavorizr.git","ref":"chore/temp-migrate-3-29","path":"."}}', + ); + + await File( + path.join( + this.path, + 'flavorizr.yaml', + ), + ).writeAsString(''' +flavors: + playStore: + app: + name: "App" + + android: + applicationId: "com.example.shorebird_test" + ios: + bundleId: "com.example.shorebird_test" + internal: + app: + name: "App (Internal)" + + android: + applicationId: "com.example.shorebird_test.internal" + ios: + bundleId: "com.example.shorebird_test.internal" + global: + app: + name: "App (Global)" + + android: + applicationId: "com.example.shorebird_test.global" + ios: + bundleId: "com.example.shorebird_test.global" +'''); + + final result = await _runFlutterCommand( + ['pub', 'run', 'flutter_flavorizr'], + workingDirectory: this, + ); + if (result.exitCode != 0) { + throw Exception( + 'Failed to run `flutter pub run flutter_flavorizr`: ${result.stderr}'); + } + } + + void addShorebirdFlavors() { + const flavors = ''' +flavors: + global: global_123 + internal: internal_123 + playStore: playStore_123 +'''; + + final currentShorebirdContent = shorebirdFile.readAsStringSync(); + shorebirdFile.writeAsStringSync( + ''' +$currentShorebirdContent +$flavors +''', + ); + } + + Future runFlutterBuildApk({ + String? flavor, + Map? environment, + }) async { + final result = await _runFlutterCommand( + [ + 'build', + 'apk', + if (flavor != null) '--flavor=$flavor', + ], + workingDirectory: this, + environment: environment, + ); + if (result.exitCode != 0) { + throw Exception('Failed to run `flutter build apk`: ${result.stderr}'); + } + } + + Future runFlutterBuildIos({ + Map? environment, + String? flavor, + }) async { + final result = await _runFlutterCommand( + // The projects used to test are generated on spot, to make it simpler we don't + // configure any apple accounts on it, so we skip code signing here. + ['build', 'ipa', '--no-codesign', if (flavor != null) '--flavor=$flavor'], + workingDirectory: this, + environment: environment, + ); + + if (result.exitCode != 0) { + throw Exception('Failed to run `flutter build ios`: ${result.stderr}'); + } + } + + File apkFile({String? flavor}) => File( + path.join( + this.path, + 'build', + 'app', + 'outputs', + 'flutter-apk', + 'app-${flavor != null ? '$flavor-' : ''}release.apk', + ), + ); + + Directory iosArchiveFile() => Directory( + path.join( + this.path, + 'build', + 'ios', + 'archive', + 'Runner.xcarchive', + ), + ); + + Future getGeneratedAndroidShorebirdYaml({String? flavor}) async { + final decodedBytes = + ZipDecoder().decodeBytes(apkFile(flavor: flavor).readAsBytesSync()); + + await extractArchiveToDisk( + decodedBytes, path.join(this.path, 'apk-extracted')); + + final yamlString = File( + path.join( + this.path, + 'apk-extracted', + 'assets', + 'flutter_assets', + 'shorebird.yaml', + ), + ).readAsStringSync(); + return loadYaml(yamlString) as YamlMap; + } + + Future getGeneratedIosShorebirdYaml() async { + final yamlString = File( + path.join( + iosArchiveFile().path, + 'Products', + 'Applications', + 'Runner.app', + 'Frameworks', + 'App.framework', + 'flutter_assets', + 'shorebird.yaml', + ), + ).readAsStringSync(); + return loadYaml(yamlString) as YamlMap; + } +} diff --git a/shorebird/ci/internal/generate_manifest.sh b/shorebird/ci/internal/generate_manifest.sh new file mode 100755 index 0000000000000..4c95de6baf098 --- /dev/null +++ b/shorebird/ci/internal/generate_manifest.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# This script outputs an artifact_manifest.yaml mapping +# a shorebird engine revision to a flutter engine revision. +# Usage: +# ./generate_manifest.sh > artifact_manifest.yaml + +set -e + +# NOTE: If you edit this file you also may need to edit the global list +# of all known artifacts in the artifact_proxy's config.dart + +if [ "$#" -ne 1 ]; then + echo "Usage: ./generate_manifest.sh " + exit 1 +fi + +FLUTTER_ENGINE_REVISION=$1 + +cat <, but that no longer seems needed. +# We always use the hermetic NDK from the engine repo. +ANDROID_NDK_HOME="$ENGINE_SRC/flutter/third_party/android_tools/ndk" \ +cargo ndk \ + --target armv7-linux-androideabi \ + --target aarch64-linux-android \ + --target i686-linux-android \ + --target x86_64-linux-android \ + build --release + +cargo build --release --target x86_64-unknown-linux-gnu + +# Build the patch tool. +cd $UPDATER_SRC/patch +cargo build --release + +# Compile the engine using the steps here: +# https://github.com/flutter/flutter/wiki/Compiling-the-engine#compiling-for-android-from-macos-or-linux +cd $ENGINE_SRC + +NINJA="ninja" +GN=./flutter/tools/gn +# We could probably use our own prebuilt dart SDK, by modifying the gn files. +GN_ARGS="--no-rbe --no-enable-unittests" + +# We could use Linux to generate all of our Android binaries, but we don't yet. +# https://github.com/flutter/engine/blob/e590b24f3962fda3ec9144dcee3f7565b195839a/ci/builders/linux_android_aot_engine.json#L40 + +# Build the default and gen_snapshot targets. +# +# Linux doesn't seem to use "archive_gen_snapshot" as a target name yet. +# https://github.com/flutter/flutter/issues/105351#issuecomment-1650686247 +ANDROID_TARGETS="default gen_snapshot" + +# Android arm64 release +$GN $GN_ARGS --android --android-cpu=arm64 --runtime-mode=release +$NINJA -C ./out/android_release_arm64 $ANDROID_TARGETS + +# Android arm32 release +$GN $GN_ARGS --runtime-mode=release --android +$NINJA -C out/android_release $ANDROID_TARGETS + +# Android x64 release +$GN $GN_ARGS --android --android-cpu=x64 --runtime-mode=release +$NINJA -C ./out/android_release_x64 $ANDROID_TARGETS + +# Build Dart and Flutter +$GN $GN_ARGS --runtime-mode=release --no-prebuilt-dart-sdk +# build Dart and the linux shell and flutter_patched_sdk_product.zip +$NINJA -C out/host_release dart_sdk flutter/shell/platform/linux:flutter_gtk flutter/build/archives:flutter_patched_sdk +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 + +# Build debug Linux artifacts +# These are output to the `linux-x64` directory in host_debug, and are used +# by `flutter build linux --release`. +$GN $GN_ARGS --no-prebuilt-dart-sdk +$NINJA -C ./out/host_debug flutter/build/archives:artifacts + +# Shorebird AOT Tools (Linker) +mkdir -p $ENGINE_OUT/host_release/aot_tools + +# Dart kernel (.dill) files are not stable and can change with the version of Dart, so we +# can't use this machine's `dart`. Here we're using the version of Dart that this +# version of the engine depends on, which should be the same version that +# `flutter` ends up depending on. +DART=$ENGINE_OUT/host_release/dart-sdk/bin/dart +AOT_TOOLS_PKG=$ENGINE_SRC/flutter/third_party/dart/pkg/aot_tools +# This should be part of `gclient sync` https://github.com/shorebirdtech/_build_engine/issues/113 +(cd $AOT_TOOLS_PKG; $DART pub get) +# This should be built as part of Dart and then pulled down as part of the engine build. +# https://github.com/shorebirdtech/_build_engine/issues/88 +$DART compile kernel $AOT_TOOLS_PKG/bin/aot_tools.dart -o $ENGINE_OUT/host_release/aot_tools/aot-tools.dill + +mkdir -p $ENGINE_OUT/host_release/updater_tools +UPDATER_TOOLS_PKG=$ENGINE_SRC/flutter/third_party/updater/updater_tools +# This should be part of `gclient sync` https://github.com/shorebirdtech/_build_engine/issues/113 + +# We could also build the `patch` tool for Linux here. diff --git a/shorebird/ci/internal/linux_setup.sh b/shorebird/ci/internal/linux_setup.sh new file mode 100755 index 0000000000000..626ad211536eb --- /dev/null +++ b/shorebird/ci/internal/linux_setup.sh @@ -0,0 +1,30 @@ +#!/bin/bash -e + +# Usage: +# ./linux_setup.sh + +# Per https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment +# Subset of ./flutter/build/install-build-deps-linux-desktop.sh +sudo apt -y install libfreetype6-dev pkg-config + +# This assumes rust is installed, but could also install rust/cargo. + +# Need NDK from https://developer.android.com/ndk/downloads +# The NDK version should match that of DEPS, e.g. +# https://github.com/flutter/flutter/blame/b45fa18946ecc2d9b4009952c636ba7e2ffbb787/DEPS#L615 +# Example: +# curl -O https://dl.google.com/android/repository/android-ndk-r27d-linux.zip +# unzip android-ndk-r27d-linux.zip +# On the GHA runners we set this in .github/workflows/build_engine.yaml +# env: +# NDK_HOME: /home/gha/bin/android-ndk-r27d + +# We require an old version of cargo-ndk to support the old NDK Flutter +# engine currently uses. +cargo install cargo-ndk +rustup target add \ + aarch64-linux-android \ + armv7-linux-androideabi \ + x86_64-linux-android \ + i686-linux-android \ + x86_64-unknown-linux-gnu diff --git a/shorebird/ci/internal/linux_test_build.sh b/shorebird/ci/internal/linux_test_build.sh new file mode 100755 index 0000000000000..be3c54da547ec --- /dev/null +++ b/shorebird/ci/internal/linux_test_build.sh @@ -0,0 +1,29 @@ +#!/bin/bash -e + +# The path to the Flutter engine. +# Convert to an absolute path so we don't need to worry about cd'ing back to +# the root directory between commands. +ENGINE_ROOT=$(realpath $1) +ENGINE_SRC=$ENGINE_ROOT/src + +cd $ENGINE_SRC + +UPDATER_SRC=$ENGINE_SRC/flutter/third_party/updater +(cd $UPDATER_SRC && + ANDROID_NDK_HOME="$ENGINE_SRC/flutter/third_party/android_tools/ndk" \ + cargo ndk \ + --target armv7-linux-androideabi \ + --target aarch64-linux-android \ + --target i686-linux-android \ + --target x86_64-linux-android \ + build --release && + cargo build --release --target x86_64-unknown-linux-gnu +) + +# Generate an unoptimized debug build of the engine (expected by the test script). +./flutter/tools/gn --unoptimized --no-rbe +ninja -C out/host_debug_unopt + +# Generate an unoptimized android debug build for java engine tests +./flutter/tools/gn --android --unoptimized --no-rbe +ninja -C out/android_debug_unopt diff --git a/shorebird/ci/internal/linux_upload.sh b/shorebird/ci/internal/linux_upload.sh new file mode 100755 index 0000000000000..873f0f3edb969 --- /dev/null +++ b/shorebird/ci/internal/linux_upload.sh @@ -0,0 +1,138 @@ +#!/bin/bash -e + +# Usage: +# ./linux_upload.sh engine_path git_hash + +# Convert to an absolute path so we don't need to worry about cd'ing back to +# the root directory between commands. +ENGINE_ROOT=$(realpath $1) +ENGINE_HASH=$2 + +STORAGE_BUCKET="download.shorebird.dev" +SHOREBIRD_ROOT=gs://$STORAGE_BUCKET/shorebird/$ENGINE_HASH + +ENGINE_SRC=$ENGINE_ROOT/src +ENGINE_OUT=$ENGINE_SRC/out +ENGINE_FLUTTER=$ENGINE_SRC/flutter +# FLUTTER_ROOT is the Flutter monorepo root (parent of engine/) +FLUTTER_ROOT=$(dirname $ENGINE_ROOT) + +cd $FLUTTER_ROOT + +# Compute the content-aware hash for the Dart SDK. +# This allows Flutter checkouts that haven't changed engine content to share +# the same pre-built Dart SDK, even if they have different git commit SHAs. +CONTENT_HASH=$($FLUTTER_ROOT/bin/internal/content_aware_hash.sh) + +# We do not generate a manifest file, we assume another builder did that. +# TODO(bryanoltman): should we generate a manifest file as part of an upload +# script, or should it be done once all build and uploads have completed? +# See https://github.com/shorebirdtech/build_engine/issues/25 + +# TODO(eseidel): This should not be in shell, it's too complicated/repetitive. + +HOST_ARCH='linux-x64' + +INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$ENGINE_HASH" +MAVEN_VER="1.0.0-$ENGINE_HASH" +MAVEN_ROOT="gs://$STORAGE_BUCKET/download.flutter.io/io/flutter" + +# Dart SDK +# This gets uploaded to flutter_infra_release/flutter/\$engine/dart-sdk-$HOST_ARCH.zip +# We also upload to the content-aware hash path to support local development branches. +CONTENT_INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$CONTENT_HASH" + +HOST_RELEASE=$ENGINE_OUT/host_release +DART_ZIP_FILE=dart-sdk-$HOST_ARCH.zip +( + cd $HOST_RELEASE; + zip -r $DART_ZIP_FILE dart-sdk +) +ZIPS_DEST=$INFRA_ROOT/$DART_ZIP_FILE +gsutil cp $HOST_RELEASE/$DART_ZIP_FILE $ZIPS_DEST +# Also upload to content-aware hash path +gsutil cp $HOST_RELEASE/$DART_ZIP_FILE $CONTENT_INFRA_ROOT/$DART_ZIP_FILE + +# Android Arm64 release Flutter artifacts +ARCH_OUT=$ENGINE_OUT/android_release_arm64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm64-release +ZIPS_DEST=$INFRA_ROOT/android-arm64-release +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip +gsutil cp $ZIPS_OUT/symbols.zip $ZIPS_DEST/symbols.zip +# Android Arm64 release Maven artifacts +ARCH_PATH=$ARCH_OUT/arm64_v8a_release +MAVEN_PATH=$MAVEN_ROOT/arm64_v8a_release/$MAVEN_VER/arm64_v8a_release-$MAVEN_VER +gsutil cp $ARCH_PATH.pom $MAVEN_PATH.pom +gsutil cp $ARCH_PATH.jar $MAVEN_PATH.jar +gsutil cp $ARCH_PATH.maven-metadata.xml $MAVEN_PATH.maven-metadata.xml + +# Android Arm32 release Flutter artifacts +ARCH_OUT=$ENGINE_OUT/android_release +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm-release +ZIPS_DEST=$INFRA_ROOT/android-arm-release +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip +gsutil cp $ZIPS_OUT/symbols.zip $ZIPS_DEST/symbols.zip +# Android Arm32 release Maven artifacts +ARCH_PATH=$ARCH_OUT/armeabi_v7a_release +MAVEN_PATH=$MAVEN_ROOT/armeabi_v7a_release/$MAVEN_VER/armeabi_v7a_release-$MAVEN_VER +gsutil cp $ARCH_PATH.pom $MAVEN_PATH.pom +gsutil cp $ARCH_PATH.jar $MAVEN_PATH.jar +gsutil cp $ARCH_PATH.maven-metadata.xml $MAVEN_PATH.maven-metadata.xml + +# Not sure which flutter_embedding_release files to use? 32 or 64 bit? +# It does not seem to contain the libflutter.so file, but does seem to +# differ between the two build dirs. +ARCH_OUT=$ENGINE_OUT/android_release +ARCH_PATH=$ARCH_OUT/flutter_embedding_release +MAVEN_PATH=$MAVEN_ROOT/flutter_embedding_release/$MAVEN_VER/flutter_embedding_release-$MAVEN_VER +gsutil cp $ARCH_PATH.pom $MAVEN_PATH.pom +gsutil cp $ARCH_PATH.jar $MAVEN_PATH.jar +gsutil cp $ARCH_PATH.maven-metadata.xml $MAVEN_PATH.maven-metadata.xml + +# Android x64 release Flutter artifacts +ARCH_OUT=$ENGINE_OUT/android_release_x64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-x64-release +ZIPS_DEST=$INFRA_ROOT/android-x64-release +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip +gsutil cp $ZIPS_OUT/symbols.zip $ZIPS_DEST/symbols.zip +# Android x64 release Maven artifacts +ARCH_PATH=$ARCH_OUT/x86_64_release +MAVEN_PATH=$MAVEN_ROOT/x86_64_release/$MAVEN_VER/x86_64_release-$MAVEN_VER +gsutil cp $ARCH_PATH.pom $MAVEN_PATH.pom +gsutil cp $ARCH_PATH.jar $MAVEN_PATH.jar +gsutil cp $ARCH_PATH.maven-metadata.xml $MAVEN_PATH.maven-metadata.xml + +# Shorebird AOT Tools (Linker) +gsutil cp $ENGINE_OUT/host_release/aot_tools/aot-tools.dill $SHOREBIRD_ROOT/aot-tools.dill + +# Common Product-mode artifacts +ARCH_OUT=$ENGINE_OUT/host_release +ZIPS_OUT=$ARCH_OUT/zip_archives +ZIPS_DEST=$INFRA_ROOT +gsutil cp $ZIPS_OUT/flutter_patched_sdk_product.zip $ZIPS_DEST/flutter_patched_sdk_product.zip + +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 +# Linux x64 host_release font_subset (ConstFinder) +# ARCH_OUT=$ENGINE_OUT/host_release +# ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +# ZIPS_DEST=$INFRA_ROOT/linux-x64-release +# gsutil cp $ZIPS_OUT/font-subset.zip $ZIPS_DEST/font-subset.zip + +# Linux Desktop Support +ARCH_OUT=$ENGINE_OUT/host_release +ZIPS_OUT=$ARCH_OUT/zip_archives/linux-x64-release +ZIPS_DEST=$INFRA_ROOT/linux-x64-release +gsutil cp $ZIPS_OUT/linux-x64-flutter-gtk.zip $ZIPS_DEST/linux-x64-flutter-gtk.zip + +ARCH_OUT=$ENGINE_OUT/host_debug +ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +ZIPS_DEST=$INFRA_ROOT/$HOST_ARCH +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip + +# We could upload patch if we built it here. +# gsutil cp $ENGINE_OUT/host_release/patch.zip $SHOREBIRD_ROOT/patch-win-x64.zip diff --git a/shorebird/ci/internal/mac_build.sh b/shorebird/ci/internal/mac_build.sh new file mode 100755 index 0000000000000..a860da431f269 --- /dev/null +++ b/shorebird/ci/internal/mac_build.sh @@ -0,0 +1,204 @@ +#!/bin/bash -e + +# FIXME: This script should be deleted and instead these steps be part +# of the GN build process. +# I haven't investigated how to build rust from GN with the Android NDK yet. + +# Usage: +# ./mac_build.sh engine_path + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 engine_path" + exit 1 +fi + +# Convert to an absolute path so we don't need to worry about cd'ing back to +# the root directory between commands. +ENGINE_ROOT=$(realpath $1) + +ENGINE_SRC=$ENGINE_ROOT/src +ENGINE_OUT=$ENGINE_SRC/out +UPDATER_SRC=$ENGINE_SRC/flutter/third_party/updater +HOST_ARCH='darwin-x64' + +# Build the Rust library. +cd $UPDATER_SRC/library + +# Build iOS and MacOS +cargo build \ + --target aarch64-apple-ios \ + --target x86_64-apple-ios \ + --target aarch64-apple-darwin \ + --target x86_64-apple-darwin \ + --release + +# Build the patch tool. +# Again, this belongs as part of the gn build. +cd $UPDATER_SRC/patch +cargo build --release + +# Compile the engine using the steps here: +# https://github.com/flutter/flutter/wiki/Compiling-the-engine#compiling-for-android-from-macos-or-linux +cd $ENGINE_SRC + +NINJA="ninja" +GN=./flutter/tools/gn +ET=./flutter/bin/et +# We could probably use our own prebuilt dart SDK, by modifying the gn files. +# `--no-enable-unittests` is needed on Flutter 3.10.1 and 3.10.2 to avoid +# https://github.com/flutter/flutter/issues/128135 +GN_ARGS="--no-rbe --no-enable-unittests" + +# FIXME: These build commands likely could build fewer targets. + +# Mac doesn't seem to use "archive_gen_snapshot" as a target name yet. +# https://github.com/flutter/flutter/issues/105351#issuecomment-1650686247 +ANDROID_TARGETS="flutter/shell/platform/android:gen_snapshot" + +# Because Flutter does not yet build universal binaries for macOS, we need to +# ensure we're building for x64 for the time being so we can support both Intel +# and Apple Silicon Macs. We do this by telling gn to use host_cpu="x64". + +# Android arm64 release +$GN $GN_ARGS --android --android-cpu=arm64 --runtime-mode=release --gn-args='host_cpu="x64"' +$NINJA -C ./out/android_release_arm64 $ANDROID_TARGETS + +# Android arm32 release +$GN $GN_ARGS --runtime-mode=release --android --gn-args='host_cpu="x64"' +$NINJA -C out/android_release $ANDROID_TARGETS + +# Android x64 release +$GN $GN_ARGS --android --android-cpu=x64 --runtime-mode=release --gn-args='host_cpu="x64"' +$NINJA -C ./out/android_release_x64 $ANDROID_TARGETS + +# We only need two targets (per the mac builders): +# "flutter/shell/platform/darwin/ios:flutter_framework", +# "flutter/lib/snapshot:generate_snapshot_bins", which builds both gen_snapshot and analyze_snapshot binaries. +# https://github.com/flutter/engine/blob/main/ci/builders/mac_ios_engine.json#L139 +# https://github.com/flutter/engine/blob/main/ci/builders/README.md +# The files created by these targets are packaged into a framework and an artifacts.zip file +# by the create_full_ios_framework.py and create_macos_framework.py scripts. + +IOS_TARGETS="flutter/shell/platform/darwin/ios:flutter_framework flutter/lib/snapshot:generate_snapshot_bins" +# You will also need to build vm_platform_strong.dill if you're using a local engine build. + +# From ci/builders/mac_host_engine.json in the engine repo +MACOS_TARGETS="flutter/shell/platform/darwin/macos:zip_macos_flutter_framework flutter/lib/snapshot:generate_snapshot_bins flutter/build/archives:artifacts" + +# Build x64 Dart SDK +$GN $GN_ARGS --runtime-mode=release --mac-cpu=x64 --no-prebuilt-dart-sdk +$NINJA -C out/host_release dart_sdk +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 + +# Build arm64 Dart SDK +$GN $GN_ARGS --runtime-mode=release --mac-cpu=arm64 --no-prebuilt-dart-sdk +$NINJA -C out/host_release_arm64 dart_sdk +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 + +# iOS arm64 release +$GN $GN_ARGS --runtime-mode=release --ios --gn-arg='shorebird_runtime=true' +$NINJA -C out/ios_release $IOS_TARGETS + +$GN $GN_ARGS --ios --runtime-mode=release --darwin-extension-safe --xcode-symlinks --gn-arg='shorebird_runtime=true' +$NINJA -C out/ios_release_extension_safe $IOS_TARGETS + +# iOS simulator-x64 release +$GN $GN_ARGS --runtime-mode=debug --ios --simulator +$NINJA -C out/ios_debug_sim $IOS_TARGETS + +$GN $GN_ARGS --runtime-mode=debug --darwin-extension-safe --ios --simulator +$NINJA -C out/ios_debug_sim_extension_safe $IOS_TARGETS + +# iOS simulator-arm64 release +$GN $GN_ARGS --runtime-mode=debug --ios --simulator --simulator-cpu=arm64 +$NINJA -C out/ios_debug_sim_arm64 $IOS_TARGETS + +$GN $GN_ARGS --runtime-mode=debug --darwin-extension-safe --ios --simulator --simulator-cpu=arm64 +$NINJA -C out/ios_debug_sim_arm64_extension_safe $IOS_TARGETS + +# macOS arm64 release +$GN $GN_ARGS --runtime-mode=release --mac --mac-cpu=arm64 +$NINJA -C out/mac_release_arm64 $MACOS_TARGETS + +# macOS x64 release +# Note: we don't enable the simulator here because the simulator is an arm64 simulator, +# which won't work for x64 apps. +$GN $GN_ARGS --runtime-mode=release --mac --mac-cpu=x64 +$NINJA -C out/mac_release $MACOS_TARGETS + +# The python scripts below fail if the out/release directory already exists. +rm -rf out/release + +# We have to create a composite Flutter.framework for iOS and macOS, matching +# what the Flutter builders do: +IOS_FRAMEWORK_OUT=out/release +echo "Building Flutter.framework for iOS" +python3 flutter/sky/tools/create_ios_framework.py \ + --dst $IOS_FRAMEWORK_OUT \ + --arm64-out-dir out/ios_release \ + --simulator-x64-out-dir out/ios_debug_sim \ + --simulator-arm64-out-dir out/ios_debug_sim_arm64 \ + --dsym \ + --strip +echo "Built Flutter.framework for iOS" + +MAC_FRAMEWORK_OUT=out/release/framework +echo "Building Flutter.framework for macOS" +python3 flutter/sky/tools/create_macos_framework.py \ + --dst $MAC_FRAMEWORK_OUT \ + --arm64-out-dir out/mac_release_arm64 \ + --x64-out-dir out/mac_release \ + --dsym \ + --strip \ + --zip +echo "Built Flutter.framework for macOS" + +echo "Creating macOS gen_snapshot" +python3 flutter/sky/tools/create_macos_gen_snapshots.py \ + --dst out/release/snapshot \ + --arm64-path out/mac_release_arm64/universal/gen_snapshot_arm64 \ + --x64-path out/mac_release/universal/gen_snapshot_x64 \ + --zip +echo "Created macOS gen_snapshot" + +# Zip the dSYMs +zip -r $IOS_FRAMEWORK_OUT/Flutter.framework.dSYM.zip $IOS_FRAMEWORK_OUT/Flutter.framework.dSYM +zip -r $MAC_FRAMEWORK_OUT/FlutterMacOS.framework.dSYM.zip $MAC_FRAMEWORK_OUT/FlutterMacOS.framework.dSYM + +sign_flutter_xcframework() { + pushd $ENGINE_OUT/release + + # Unzip the artifacts zip file, which contains the Flutter.xcframework. + rm -rf artifacts + unzip artifacts.zip -d artifacts + + # Keep a copy of the old artifacts.zip for now, we may decide to remove this later + mv artifacts.zip artifacts.old.zip + + # Sign the Flutter.xcframework + cd artifacts + + # In case the artifacts are already signed, remove the signature + codesign -v --remove-signature Flutter.xcframework + codesign -v --sign "Apple Distribution: Code Town Inc (6V53YACS2W)" Flutter.xcframework + + # Zip the artifacts back up + zip -r "../artifacts.zip" * + + # Cleanup + cd .. + rm -rf artifacts + + popd +} + +sign_flutter_xcframework + +# Create out/engine_stamp.json +# We can remove this explicit step once we're using et in any of the lines +# above. +$ET stamp diff --git a/shorebird/ci/internal/mac_setup.sh b/shorebird/ci/internal/mac_setup.sh new file mode 100755 index 0000000000000..8453f8b9b1a9e --- /dev/null +++ b/shorebird/ci/internal/mac_setup.sh @@ -0,0 +1,11 @@ +#!/bin/bash -e + +# Usage: +# ./mac_setup.sh + +# This assumes rust is installed, but could also install rust/cargo. +rustup target add \ + x86_64-apple-ios \ + aarch64-apple-ios \ + aarch64-apple-darwin \ + x86_64-apple-darwin diff --git a/shorebird/ci/internal/mac_upload.sh b/shorebird/ci/internal/mac_upload.sh new file mode 100755 index 0000000000000..8ec266246a8e1 --- /dev/null +++ b/shorebird/ci/internal/mac_upload.sh @@ -0,0 +1,180 @@ +#!/bin/bash -e + +# Usage: +# ./mac_upload.sh engine_path git_hash + +# Convert to an absolute path so we don't need to worry about cd'ing back to +# the root directory between commands. +ENGINE_ROOT=$(realpath $1) +ENGINE_HASH=$2 + +# Get the absolute path to the directory of this script. +SCRIPT_DIR=$(cd $(dirname $0) && pwd) + +STORAGE_BUCKET="download.shorebird.dev" +SHOREBIRD_ROOT=gs://$STORAGE_BUCKET/shorebird/$ENGINE_HASH + +ENGINE_SRC=$ENGINE_ROOT/src +ENGINE_OUT=$ENGINE_SRC/out +ENGINE_FLUTTER=$ENGINE_SRC/flutter +# FLUTTER_ROOT is the Flutter monorepo root (parent of engine/) +FLUTTER_ROOT=$(dirname $ENGINE_ROOT) + +cd $FLUTTER_ROOT + +# Compute the content-aware hash for the Dart SDK. +# This allows Flutter checkouts that haven't changed engine content to share +# the same pre-built Dart SDK, even if they have different git commit SHAs. +CONTENT_HASH=$($FLUTTER_ROOT/bin/internal/content_aware_hash.sh) +# Can't just `git merge-base` because the engine branches for each +# major version (e.g. 3.7, 3.8) (e.g. upstream/flutter-3.7-candidate.1) +# but it's not clear which branch we're forked from, only that we took +# some tag and added our commits (but we don't know what tag). +BASE_FLUTTER_TAG=`git describe --tags --abbrev=0` +# Read the first line from bin/internal/engine.version file and trim whitespace. +BASE_ENGINE_HASH=`git show $BASE_FLUTTER_TAG:bin/internal/engine.version | head -n 1 | tr -d '[:space:]'` + +# Build the artifacts manifest: +MANIFEST_FILE=`mktemp` +# Note that any uploads which are *not* listed in the manifest will be +# ignored by the artifact proxy. +# if you add uploads here, they also need to be reflected in the manifest. +$SCRIPT_DIR/generate_manifest.sh $BASE_ENGINE_HASH > $MANIFEST_FILE + +# FIXME: This should not be in shell, it's too complicated/repetitive. +# Only need the libflutter.so (and flutter.jar) artifacts +# Artifact list: https://github.com/shorebirdtech/shorebird/blob/main/packages/artifact_proxy/lib/config.dart + +HOST_ARCH='darwin-x64' +ARM64_HOST_ARCH='darwin-arm64' + +INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$ENGINE_HASH" + +# engine_stamp.json +ENGINE_STAMP_FILE=$ENGINE_OUT/engine_stamp.json +gsutil cp $ENGINE_STAMP_FILE $INFRA_ROOT/engine_stamp.json + +# Dart SDK +# This gets uploaded to flutter_infra_release/flutter/\$engine/dart-sdk-$HOST_ARCH.zip +# We also upload to the content-aware hash path to support local development branches. +CONTENT_INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$CONTENT_HASH" + +# x64 Dart SDK +HOST_RELEASE=$ENGINE_OUT/host_release +DART_ZIP_FILE=dart-sdk-$HOST_ARCH.zip +( + cd $HOST_RELEASE; + zip -r $DART_ZIP_FILE dart-sdk +) +ZIPS_DEST=$INFRA_ROOT/$DART_ZIP_FILE +gsutil cp $HOST_RELEASE/$DART_ZIP_FILE $ZIPS_DEST +# Also upload to content-aware hash path +gsutil cp $HOST_RELEASE/$DART_ZIP_FILE $CONTENT_INFRA_ROOT/$DART_ZIP_FILE + +# arm64 Dart SDK +HOST_RELEASE_ARM64=$ENGINE_OUT/host_release_arm64 +DART_ZIP_FILE=dart-sdk-$ARM64_HOST_ARCH.zip +( + cd $HOST_RELEASE_ARM64; + zip -r $DART_ZIP_FILE dart-sdk +) +ZIPS_DEST=$INFRA_ROOT/$DART_ZIP_FILE +gsutil cp $HOST_RELEASE_ARM64/$DART_ZIP_FILE $ZIPS_DEST +# Also upload to content-aware hash path +gsutil cp $HOST_RELEASE_ARM64/$DART_ZIP_FILE $CONTENT_INFRA_ROOT/$DART_ZIP_FILE + +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 +# # mac x64 host_release font_subset (ConstFinder) +# ARCH_OUT=$ENGINE_OUT/host_release +# ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +# ZIPS_DEST=$INFRA_ROOT/darwin-x64-release +# gsutil cp $ZIPS_OUT/font-subset.zip $ZIPS_DEST/font-subset.zip + +# # mac arm64 host_release font_subset (ConstFinder) +# ARCH_OUT=$ENGINE_OUT/host_release_arm64 +# ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +# ZIPS_DEST=$INFRA_ROOT/darwin-arm64-release +# gsutil cp $ZIPS_OUT/font-subset.zip $ZIPS_DEST/font-subset.zip + +# Android Arm64 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release_arm64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm64-release +ZIPS_DEST=$INFRA_ROOT/android-arm64-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# Android Arm32 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm-release +ZIPS_DEST=$INFRA_ROOT/android-arm-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# Android x64 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release_x64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-x64-release +ZIPS_DEST=$INFRA_ROOT/android-x64-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# Match the upload pattern from iOS: +# https://github.com/flutter/engine/commit/1d7f0c66c316a37105601b13136f890f6595aebc + +# iOS release Flutter artifacts +ARCH_OUT=$ENGINE_OUT/release +ZIPS_OUT=$ARCH_OUT +ZIPS_DEST=$INFRA_ROOT/ios-release +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip + +# iOS dSYM +gsutil cp $ZIPS_OUT/Flutter.framework.dSYM.zip $ZIPS_DEST/Flutter.framework.dSYM.zip + +# macOS framework +ARCH_OUT=$ENGINE_OUT/release +ZIPS_OUT=$ARCH_OUT/framework +ZIPS_DEST=$INFRA_ROOT/darwin-x64-release +gsutil cp $ZIPS_OUT/framework.zip $ZIPS_DEST/framework.zip + +# macOS gen_snapshot +ARCH_OUT=$ENGINE_OUT/release +ZIPS_OUT=$ARCH_OUT/snapshot +ZIPS_DEST=$INFRA_ROOT/darwin-x64-release +gsutil cp $ZIPS_OUT/gen_snapshot.zip $ZIPS_DEST/gen_snapshot.zip + +# FIXME: these should go where we're putting the arm64 macOS artifacts +# (darwin-x64-release), however, arm macs use darwin-x64-release and we +# currently only support those. We need to find a way to support both. +# macOS x64 release artifacts +# ARCH_OUT=$ENGINE_OUT/mac_release +# ZIPS_OUT=$ARCH_OUT/zip_archives/darwin-x64-release +# ZIPS_DEST=$INFRA_ROOT/darwin-x64-release +# gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip + +# macOS arm64 release artifacts +ARCH_OUT=$ENGINE_OUT/mac_release_arm64 +ZIPS_OUT=$ARCH_OUT/zip_archives/darwin-arm64-release +# This looks wrong - why are we putting arm64 artifacts in darwin-x64-release +# instead of darwin-arm64-release? This is because arm macs use darwin-x64-release +# and we need to use the artifacts we've built for arm64 macs. +ZIPS_DEST=$INFRA_ROOT/darwin-x64-release +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip + +# macOS dSYM (used for symbolication, not by Flutter) +ARCH_OUT=$ENGINE_OUT/release +ZIPS_OUT=$ARCH_OUT/framework +ZIPS_DEST=$INFRA_ROOT/darwin-x64 +gsutil cp $ZIPS_OUT/FlutterMacOS.framework.dSYM.zip $ZIPS_DEST/FlutterMacOS.framework.dSYM.zip + +TMP_DIR=$(mktemp -d) + +PATCH_VERSION=0.2.1 +GH_RELEASE=https://github.com/shorebirdtech/updater/releases/download/patch-v$PATCH_VERSION/ +cd $TMP_DIR +curl -L $GH_RELEASE/patch-x86_64-apple-darwin.zip -o patch-x86_64-apple-darwin.zip +curl -L $GH_RELEASE/patch-x86_64-pc-windows-msvc.zip -o patch-x86_64-pc-windows-msvc.zip +curl -L $GH_RELEASE/patch-x86_64-unknown-linux-musl.zip -o patch-x86_64-unknown-linux-musl.zip + +gsutil cp patch-x86_64-apple-darwin.zip $SHOREBIRD_ROOT/patch-darwin-x64.zip +gsutil cp patch-x86_64-pc-windows-msvc.zip $SHOREBIRD_ROOT/patch-windows-x64.zip +gsutil cp patch-x86_64-unknown-linux-musl.zip $SHOREBIRD_ROOT/patch-linux-x64.zip + +gsutil cp $MANIFEST_FILE $SHOREBIRD_ROOT/artifacts_manifest.yaml diff --git a/shorebird/ci/internal/win_build.sh b/shorebird/ci/internal/win_build.sh new file mode 100755 index 0000000000000..2df02670aa78f --- /dev/null +++ b/shorebird/ci/internal/win_build.sh @@ -0,0 +1,63 @@ +#!/bin/bash -e + +# Usage: +# ./win_build.sh engine_path + +ENGINE_ROOT=$1 + +ENGINE_SRC=$ENGINE_ROOT/src +ENGINE_OUT=$ENGINE_SRC/out +UPDATER_SRC=$ENGINE_SRC/flutter/third_party/updater +HOST_ARCH='windows-x64' + +# Build the Rust library. +cd $UPDATER_SRC/library + +cargo build --release \ + --target x86_64-pc-windows-msvc + +# Compile the engine using the steps here: +# https://github.com/flutter/flutter/wiki/Compiling-the-engine#compiling-for-android-from-macos-or-linux +cd $ENGINE_SRC + +NINJA="ninja" +GN=./flutter/tools/gn +# We could probably use our own prebuilt dart SDK, by modifying the gn files. +GN_ARGS="--no-rbe --no-enable-unittests" + +# Windows only needs gen_snapshot for each Android CPU type. +# See https://github.com/flutter/engine/blob/e590b24f3962fda3ec9144dcee3f7565b195839a/ci/builders/windows_android_aot_engine.json + +TARGETS="archive_win_gen_snapshot" + +# Build host_release +$GN $GN_ARGS --runtime-mode=release --no-prebuilt-dart-sdk +$NINJA -C out/host_release dart_sdk +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 + +# Build windows desktop targets +$GN $GN_ARGS --runtime-mode=release --no-prebuilt-dart-sdk +$NINJA -C ./out/host_release flutter/build/archives:windows_flutter gen_snapshot windows flutter/build/archives:artifacts + +# Build debug Windows artifacts +# These are output to the `windows-x64` directory in host_debug, and are used +# by `flutter build windows --release`. +$GN $GN_ARGS --no-prebuilt-dart-sdk +$NINJA -C ./out/host_debug flutter/build/archives:artifacts + +# If this gives you trouble, try using VS2019 instead. I had trouble with 2022. +# Android arm64 release +$GN $GN_ARGS --android --android-cpu=arm64 --runtime-mode=release +$NINJA -C ./out/android_release_arm64 $TARGETS + +# Android arm32 release +$GN $GN_ARGS --runtime-mode=release --android +$NINJA -C out/android_release $TARGETS + +# Android x64 release +$GN $GN_ARGS --android --android-cpu=x64 --runtime-mode=release +$NINJA -C ./out/android_release_x64 $TARGETS + +# We could also build the `patch` tool for Windows here. diff --git a/shorebird/ci/internal/win_setup.sh b/shorebird/ci/internal/win_setup.sh new file mode 100755 index 0000000000000..971135644f66b --- /dev/null +++ b/shorebird/ci/internal/win_setup.sh @@ -0,0 +1,8 @@ +#!/bin/bash -e + +# Usage: +# ./windows_setup.sh + +# Add the MSVC toolchain to Rust. +rustup target add \ + x86_64-pc-windows-msvc diff --git a/shorebird/ci/internal/win_upload.sh b/shorebird/ci/internal/win_upload.sh new file mode 100755 index 0000000000000..952457109e40c --- /dev/null +++ b/shorebird/ci/internal/win_upload.sh @@ -0,0 +1,90 @@ +#!/bin/bash -e + +# Usage: +# ./win_upload.sh engine_path git_hash +ENGINE_ROOT=$1 +ENGINE_HASH=$2 + +STORAGE_BUCKET="download.shorebird.dev" +SHOREBIRD_ROOT=gs://$STORAGE_BUCKET/shorebird/$ENGINE_HASH + +ENGINE_SRC=$ENGINE_ROOT/src +ENGINE_OUT=$ENGINE_SRC/out +ENGINE_FLUTTER=$ENGINE_SRC/flutter +# FLUTTER_ROOT is the Flutter monorepo root (parent of engine/) +FLUTTER_ROOT=$(dirname $ENGINE_ROOT) + +cd $FLUTTER_ROOT + +# Compute the content-aware hash for the Dart SDK. +# This allows Flutter checkouts that haven't changed engine content to share +# the same pre-built Dart SDK, even if they have different git commit SHAs. +CONTENT_HASH=$($FLUTTER_ROOT/bin/internal/content_aware_hash.sh) + +# We do not generate a manifest file, we assume another builder did that. + +# TODO(eseidel): This should not be in shell, it's too complicated/repetitive. + +HOST_ARCH='windows-x64' + +INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$ENGINE_HASH" + +# Dart SDK +# This gets uploaded to flutter_infra_release/flutter/\$engine/dart-sdk-$HOST_ARCH.zip +# We also upload to the content-aware hash path to support local development branches. +CONTENT_INFRA_ROOT="gs://$STORAGE_BUCKET/flutter_infra_release/flutter/$CONTENT_HASH" + +DART_SDK_DIR=$ENGINE_OUT/host_release/dart-sdk +DART_ZIP_FILE=dart-sdk-$HOST_ARCH.zip + +# Use 7zip to compress the Dart SDK, as zip isn't available on Windows and +# Powershell, which we would normally use in the form of +# `powershell Compress-Archive dart-sdk dart-sdk.zip`, doesn't play nicely +# with git bash paths (e.g. /c/Users/... instead of C:/Users/...) +/c/Program\ Files/7-Zip/7z a $DART_ZIP_FILE $DART_SDK_DIR +ZIPS_DEST=$INFRA_ROOT/$DART_ZIP_FILE +gsutil cp $DART_ZIP_FILE $ZIPS_DEST +# Also upload to content-aware hash path +gsutil cp $DART_ZIP_FILE $CONTENT_INFRA_ROOT/$DART_ZIP_FILE + +# Android Arm64 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release_arm64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm64-release +ZIPS_DEST=$INFRA_ROOT/android-arm64-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# Android Arm32 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release +ZIPS_OUT=$ARCH_OUT/zip_archives/android-arm-release +ZIPS_DEST=$INFRA_ROOT/android-arm-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# Android x64 release gen_snapshot +ARCH_OUT=$ENGINE_OUT/android_release_x64 +ZIPS_OUT=$ARCH_OUT/zip_archives/android-x64-release +ZIPS_DEST=$INFRA_ROOT/android-x64-release +gsutil cp $ZIPS_OUT/$HOST_ARCH.zip $ZIPS_DEST/$HOST_ARCH.zip + +# We could upload patch if we built it here. +# gsutil cp $ENGINE_OUT/host_release/patch.zip $SHOREBIRD_ROOT/patch-win-x64.zip + +# Engine release artifacts +ARCH_OUT=$ENGINE_OUT/host_release +ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH-release +ZIPS_DEST=$INFRA_ROOT/$HOST_ARCH-release +gsutil cp $ZIPS_OUT/$HOST_ARCH-flutter.zip $ZIPS_DEST/$HOST_ARCH-flutter.zip + +# We want to build flutter/tools/font_subset, but that doesn't work with +# --no-prebuilt-dart-sdk. +# https://github.com/flutter/flutter/issues/164531 +# # Windows x64 host_release font_subset (ConstFinder) +# ARCH_OUT=$ENGINE_OUT/host_release +# ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +# ZIPS_DEST=$INFRA_ROOT/windows-x64-release +# gsutil cp $ZIPS_OUT/font-subset.zip $ZIPS_DEST/font-subset.zip + +# Engine debug artifacts (not sure why this is needed?) +ARCH_OUT=$ENGINE_OUT/host_debug +ZIPS_OUT=$ARCH_OUT/zip_archives/$HOST_ARCH +ZIPS_DEST=$INFRA_ROOT/$HOST_ARCH +gsutil cp $ZIPS_OUT/artifacts.zip $ZIPS_DEST/artifacts.zip diff --git a/shorebird/ci/linux_build_and_upload.sh b/shorebird/ci/linux_build_and_upload.sh new file mode 100755 index 0000000000000..9657e14178695 --- /dev/null +++ b/shorebird/ci/linux_build_and_upload.sh @@ -0,0 +1,32 @@ +#!/bin/bash -e + +# Usage: +# ./linux_build_and_upload.sh flutter_root engine_hash +# +# This is the main entrypoint for building and uploading Linux engine artifacts. +# It is called from the _build_engine repository's CI scripts. + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 flutter_root engine_hash" + exit 1 +fi + +FLUTTER_ROOT=$1 +ENGINE_HASH=$2 +ENGINE_ROOT=$FLUTTER_ROOT/engine + +# Get the absolute path to the directory of this script. +SCRIPT_DIR=$(cd $(dirname $0) && pwd) + +echo "Building engine at $ENGINE_ROOT and uploading to gs://download.shorebird.dev" + +cd $SCRIPT_DIR + +# Run the setup script. +./internal/linux_setup.sh + +# Then run the build. +./internal/linux_build.sh $ENGINE_ROOT + +# Copy Shorebird engine artifacts to Google Cloud Storage. +./internal/linux_upload.sh $ENGINE_ROOT $ENGINE_HASH diff --git a/shorebird/ci/mac_build_and_upload.sh b/shorebird/ci/mac_build_and_upload.sh new file mode 100755 index 0000000000000..9ee302620d207 --- /dev/null +++ b/shorebird/ci/mac_build_and_upload.sh @@ -0,0 +1,32 @@ +#!/bin/bash -e + +# Usage: +# ./mac_build_and_upload.sh flutter_root engine_hash +# +# This is the main entrypoint for building and uploading macOS engine artifacts. +# It is called from the _build_engine repository's CI scripts. + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 flutter_root engine_hash" + exit 1 +fi + +FLUTTER_ROOT=$1 +ENGINE_HASH=$2 +ENGINE_ROOT=$FLUTTER_ROOT/engine + +# Get the absolute path to the directory of this script. +SCRIPT_DIR=$(cd $(dirname $0) && pwd) + +echo "Building engine at $ENGINE_ROOT and uploading to gs://download.shorebird.dev" + +cd $SCRIPT_DIR + +# Run the setup script. +./internal/mac_setup.sh + +# Then run the build. +./internal/mac_build.sh $ENGINE_ROOT + +# Copy Shorebird engine artifacts to Google Cloud Storage. +./internal/mac_upload.sh $ENGINE_ROOT $ENGINE_HASH diff --git a/shorebird/ci/win_build_and_upload.sh b/shorebird/ci/win_build_and_upload.sh new file mode 100755 index 0000000000000..bbda403ff2c67 --- /dev/null +++ b/shorebird/ci/win_build_and_upload.sh @@ -0,0 +1,32 @@ +#!/bin/bash -e + +# Usage: +# ./win_build_and_upload.sh flutter_root engine_hash +# +# This is the main entrypoint for building and uploading Windows engine artifacts. +# It is called from the _build_engine repository's CI scripts. + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 flutter_root engine_hash" + exit 1 +fi + +FLUTTER_ROOT=$1 +ENGINE_HASH=$2 +ENGINE_ROOT=$FLUTTER_ROOT/engine + +# Get the absolute path to the directory of this script. +SCRIPT_DIR=$(cd $(dirname $0) && pwd) + +echo "Building engine at $ENGINE_ROOT and uploading to gs://download.shorebird.dev" + +cd $SCRIPT_DIR + +# Run the setup script. +./internal/win_setup.sh + +# Then run the build. +./internal/win_build.sh $ENGINE_ROOT + +# Copy Shorebird engine artifacts to Google Cloud Storage. +./internal/win_upload.sh $ENGINE_ROOT $ENGINE_HASH diff --git a/shorebird/docs/BUILDING.md b/shorebird/docs/BUILDING.md new file mode 100644 index 0000000000000..dfd3c655a1324 --- /dev/null +++ b/shorebird/docs/BUILDING.md @@ -0,0 +1,44 @@ +# Building the Shorebird Engine Locally + +This document explains how to build the Shorebird engine locally for different platforms. + +All commands assume you are running from the `engine/src` directory. + +## Prerequisites + +- Follow the standard Flutter engine setup instructions +- Ensure you have the necessary toolchains installed for your target platform + +## macOS + +### iOS (arm64) + +```bash +./flutter/tools/gn --no-rbe --no-enable-unittests --runtime-mode=release --ios --gn-arg='shorebird_runtime=true' +ninja -C out/ios_release flutter/shell/platform/darwin/ios:flutter_framework flutter/lib/snapshot:generate_snapshot_bins +``` + +### Android arm64 + +```bash +./flutter/tools/gn --no-rbe --no-enable-unittests --android --android-cpu=arm64 --runtime-mode=release --gn-args='host_cpu="x64"' +ninja -C out/android_release_arm64 flutter/shell/platform/android:gen_snapshot +``` + +## Windows + +### Android arm64 + +```bash +./flutter/tools/gn --no-rbe --no-enable-unittests --android --android-cpu=arm64 --runtime-mode=release +ninja -C out/android_release_arm64 archive_win_gen_snapshot +``` + +## Linux + +### Android arm64 + +```bash +./flutter/tools/gn --no-rbe --no-enable-unittests --android --android-cpu=arm64 --runtime-mode=release +ninja -C out/android_release_arm64 default gen_snapshot +```