From 3eead6b0480ba4aacab8f0e0d058ac77f550bc1d Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Thu, 9 Oct 2025 10:29:07 -0500 Subject: [PATCH 001/105] [3.38] Create `release-candidate-branch.version` & `engine.version` (#176746) Part of https://github.com/flutter/flutter/issues/176744. The `engine.version` is set to the SHA cutoff point for this beta release -- https://github.com/flutter/flutter/commit/df87ee3db00df61d882f99e655a3dc5f8387f806 **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 1 + bin/internal/release-candidate-branch.version | 1 + 2 files changed, 2 insertions(+) create mode 100644 bin/internal/engine.version create mode 100644 bin/internal/release-candidate-branch.version diff --git a/bin/internal/engine.version b/bin/internal/engine.version new file mode 100644 index 0000000000000..449707cf02e18 --- /dev/null +++ b/bin/internal/engine.version @@ -0,0 +1 @@ +df87ee3db00df61d882f99e655a3dc5f8387f806 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 From 2b8e65b526f5f2c3fdfa5e85790f4e3263bfdbb3 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Fri, 10 Oct 2025 13:16:03 -0500 Subject: [PATCH 002/105] Trigger an engine build for the 3.38 beta release (#176842) The file added will be deleted. This is just to trigger an engine build. Work around for https://github.com/flutter/flutter/issues/176838. --- engine/TRIGGER.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 engine/TRIGGER.md diff --git a/engine/TRIGGER.md b/engine/TRIGGER.md new file mode 100644 index 0000000000000..60d0a99c321ed --- /dev/null +++ b/engine/TRIGGER.md @@ -0,0 +1,2 @@ + +This file is purely to trigger an engine release build and will be deleted in a future commit pre-release. \ No newline at end of file From ced5a9334ed517ae2102e120be6d334c6afcd7e2 Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Mon, 13 Oct 2025 08:29:10 -0700 Subject: [PATCH 003/105] [CP-Beta] fix: content hash check for LUCI_CONTEXT (#176867) (#176883) When running on LUCI, the environment variable is LUCI_CONTEXT fixes: #176838 --- bin/internal/content_aware_hash.ps1 | 2 +- bin/internal/content_aware_hash.sh | 2 +- dev/tools/test/content_aware_hash_test.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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/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')); }); From 2d15161f8d6fdde56918875101fe8c27173ec69c Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:55:09 -0500 Subject: [PATCH 004/105] Update `engine.version` (#176799) Sets `engine.version` to release build from https://github.com/flutter/flutter/commit/3eead6b0480ba4aacab8f0e0d058ac77f550bc1d. Part of https://github.com/flutter/flutter/issues/176744 **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 449707cf02e18..eea2c9b282ba3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -df87ee3db00df61d882f99e655a3dc5f8387f806 +ced5a9334ed517ae2102e120be6d334c6afcd7e2 From 060c2cc550a0b0d37aa48d40b5f1bb8984b7439a Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 17 Oct 2025 13:51:19 -0700 Subject: [PATCH 005/105] Trigger engine build, and clean up trigger file (#177181) My PR updating engine.version (https://github.com/flutter/flutter/pull/177178) for the 3.38.0 beta release isn't passing the analyzer because the engine artifacts don't exist. This PR will trigger another engine build, and then I'll use its merge SHA in engine.version. And it conveniently deletes the file used for this same purpose in https://github.com/flutter/flutter/pull/176842. --- engine/TRIGGER.md | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 engine/TRIGGER.md diff --git a/engine/TRIGGER.md b/engine/TRIGGER.md deleted file mode 100644 index 60d0a99c321ed..0000000000000 --- a/engine/TRIGGER.md +++ /dev/null @@ -1,2 +0,0 @@ - -This file is purely to trigger an engine release build and will be deleted in a future commit pre-release. \ No newline at end of file From 7e592fef326466f8faafa664eac2912bb0b91fd5 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 17 Oct 2025 16:08:19 -0700 Subject: [PATCH 006/105] 3.38.0 beta engine version (#177178) The version I set in https://github.com/flutter/flutter/pull/176799 was incorrect so the release build failed. This updates it to the correct engine version. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index eea2c9b282ba3..4d1a932840446 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ced5a9334ed517ae2102e120be6d334c6afcd7e2 +060c2cc550a0b0d37aa48d40b5f1bb8984b7439a From 53f281909795ed675e1a03535b2bb458603fb978 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:06:50 -0500 Subject: [PATCH 007/105] [CP-beta][Android] Refactor `ImageReaderSurfaceProducer` restoration after app resumes (#177121) > [!NOTE] > To release engineer: this can definitely wait to be included in a hotfix beta release. I also want to CP this to stable: https://github.com/flutter/flutter/pull/177112 ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/173770 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Mitigates a memory leak that occurs on Android, when `Activities` are not kept upon exit and an Activity is exited and re-entered. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Memory leak that will occur in production app but does not impact development. ### Workaround: Is there a workaround for this issue? Not that I know of. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Follow the steps in the [issue description](https://github.com/flutter/flutter/issues/173770#issue-3322196704), roughly: 1. Create a Flutter project. 2. Enter the developer options, set not to keep activities, (destroy each activity as soon as the user leaves it) 3. Entering the activity, clicking the home button, exiting the activity, and then entering the activity again will trigger the destruction and reconstruction of the activity. 4. Check memory leaks through profiler and find memory leaks. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- .../FlutterActivityAndFragmentDelegate.java | 1 + .../engine/renderer/FlutterRenderer.java | 40 +++++++------- ...lutterActivityAndFragmentDelegateTest.java | 10 ++++ .../engine/renderer/FlutterRendererTest.java | 55 +++++++------------ 4 files changed, 51 insertions(+), 55 deletions(-) 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/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/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); + } } From 7c3f912c87e2dd4d661ac6998d28e91bf7121140 Mon Sep 17 00:00:00 2001 From: Jessy Yameogo Date: Mon, 27 Oct 2025 13:18:06 -0400 Subject: [PATCH 008/105] [beta] CP: Fixes hot reload/restart crashes after closing browser tab on web-server device (#177456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Impacted Users:** Flutter web developers using the `web-server` device for hot reload/restart. **Impact Description:** Hot reload/restart crashes when the browser tab is closed, causing “Bad state: No element” errors and breaking the DWDS connection. **Workaround:** Rerun the app. **Risk:** Low — changes only affect hot reload/restart handling when no clients are connected. **Test Coverage:** Yes — covered by automated integration tests and verified with manual testing across reload/restart scenarios. **Validation Steps:** 1. run the app on webserver `flutter run -d web-server` 2. open the url 3. do hot reload 4. close the browser 5. do hot reload You should see a warning `WebSocketProxyService: No clients available.` along with `Recompile complete. No client connected.` printed in the console. The app should no longer crash. **Merged PR:** https://github.com/flutter/flutter/pull/177026 **Changes in DWDS (Parent PR):** [https://github.com/dart-lang/webdev/pull/2699](https://github.com/dart-lang/webdev/pull/2699) Fixes https://github.com/flutter/flutter/issues/174791 --- .../lib/src/isolated/resident_web_runner.dart | 59 ++++++++++++++-- packages/flutter_tools/pubspec.yaml | 4 +- .../resident_web_runner_test.dart | 4 +- .../hot_reload_websocket_test.dart | 70 ++++++++++++++++++- .../test_data/websocket_dwds_test_common.dart | 18 ++--- 5 files changed, 133 insertions(+), 22 deletions(-) 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..52209aee4a628 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -88,6 +88,8 @@ 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, { @@ -404,6 +406,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 +496,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 +511,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; 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/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 8e1017a7a879a..045a4b03efb49 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 @@ -963,7 +963,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 +1166,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, 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/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: () { From 067045cd78eb81a60d4fb0505209311abf4cbb9c Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:20:21 -0700 Subject: [PATCH 009/105] [CP-beta]Fix accessibility events not being correctly translated to ATK (#177427) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/176360 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Fix accessibility events regression on Linux which makes apps not announced with screen reader. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The Linux accessibility code was not correctly updated to new API which caused the focus events to no longer be reported. This means using a Linux app with an accessibility tool like a screen reader to not function correctly. ### Workaround: Is there a workaround for this issue? No workaround other than using a version of Flutter < 3.25. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Create a basic skeleton app with text buttons 2. Turn on the screen reader 3. Focus a button, and hear announcement when the button gets focus --- .../platform/linux/fl_accessible_node.cc | 97 +++--- .../shell/platform/linux/fl_accessible_node.h | 2 +- .../platform/linux/fl_accessible_node_test.cc | 283 +++++++++++++++--- .../shell/platform/linux/testing/mock_gtk.cc | 9 + .../shell/platform/linux/testing/mock_gtk.h | 4 + 5 files changed, 324 insertions(+), 71 deletions(-) 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/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; }; From 252283499f2c788f6e5c4841afff43d25aef0fb2 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:49:08 -0700 Subject: [PATCH 010/105] =?UTF-8?q?[CP-beta]Add=20structured=20warning=20e?= =?UTF-8?q?vent=20for=20slow=20wireless=20debugging=20on=20iOS=2026+=20d?= =?UTF-8?q?=E2=80=A6=20(#176976)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: https://github.com/flutter/flutter/issues/176206 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Warns the developer that wireless debugging may be slow on iOS 26 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Debugging wirelessly on iOS 26 may be slow. This warning suggests that the developer use a wired connection. Additionally, this will be surfaced in IDEs: https://github.com/Dart-Code/Dart-Code/issues/5730 ### Workaround: Is there a workaround for this issue? The tool is proposing the workaround. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Connect an iPhone running iOS 26 wirelessly, `flutter run`. --- packages/flutter_tools/doc/daemon.md | 12 +++ .../flutter_tools/lib/src/ios/devices.dart | 31 +++++++ .../ios/ios_device_start_prebuilt_test.dart | 80 +++++++++++++++++++ 3 files changed, 123 insertions(+) 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/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index bbcca01aae9f9..71c302ebffe9e 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:'); 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(() { From 069ba6054df5d7ddb4398c673980288cfab1533c Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:16:06 -0700 Subject: [PATCH 011/105] [CP-beta][tool/dap] Forward app.warning events from Flutter to DAP client (#176997) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/176206 / https://github.com/Dart-Code/Dart-Code/issues/5730 This is related to another cherry-pick at https://github.com/flutter/flutter/pull/176976. That cherry-pick adds a warning to `flutter run` and this cherry-pick ensures the warning is forwarded correctly to DAP clients (like VS Code). ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Warns the developer that wireless debugging may be slow on iOS 26 in VS Code. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Debugging wirelessly on iOS 26 may be slow. This change forwards the warning (which is being cherry-picked by https://github.com/flutter/flutter/pull/176976) to DAP clients so that it can be shown more prominently in VS Code. ### Workaround: Is there a workaround for this issue? This change is to show a workaround for the slow debugging to the user. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Testing requires using a DAP client. The automated test verifies the event is forwarded, and I tested manually with the Dart-Code changes when I added this change (screenshots at https://github.com/Dart-Code/Dart-Code/issues/5730#issuecomment-3389479520). --- .../src/debug_adapters/flutter_adapter.dart | 4 +++ .../dap/flutter_adapter_test.dart | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+) 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/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', () { From 082bd44a7cd382faa0e63e7ffc84b7115dd6444a Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:53:59 -0700 Subject: [PATCH 012/105] [CP-beta]Configure FfiNative resolver on dart:io (#177308) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: None ### Changelog Description: Calling `FileSystemEntity.watch(...)` will throw on Mac OS and Windows. ### Impact Description: Calling `FileSystemEntity.watch(...)` will throw on Mac OS and Windows, instead of correctly watching the path. ### Workaround: No user level work-around. `dart:io` is broken. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? It's tested by tests in Dart SDK ### Validation Steps: Run a Mac OS or Windows app with the following `main`. It should do nothing - rather than throw an exception. ```dart import 'dart:async'; import 'dart:io'; void main() async { final sub = Directory.systemTemp.watch(recursive: true).listen((_) {}); await Future.delayed(Duration(seconds: 1)); sub.cancel(); } ``` --- engine/src/flutter/lib/io/dart_io.cc | 3 +++ 1 file changed, 3 insertions(+) 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]; From d7ec7e8064d93a8d8bdd418103ec48cfafbc4841 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:55:52 -0700 Subject: [PATCH 013/105] [CP-beta] Fix crash when NSAttributedString is passed to insertText on macOS (#177401) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? There does not appear to be a dedicated issue. The issue description can be found in the PR description: https://github.com/flutter/flutter/pull/176329 The PR fixes a macOS text input crash caused by down-casting the string argument from `Any` to a `NSString`, from [this API](https://developer.apple.com/documentation/appkit/nstextinputclient/inserttext(_:replacementrange:)#parameters). The documentation says it can either be a `NSString` or `NSAttributedString` ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples > Fixes a crash on macOS when the input method (or other services) inserts a `NSAttributedString` instead of `NSString` into a text field. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) App crashes on macOS when interacting with certain IMEs or other system services, if they decided to use `NSAttributedString` instead of `NSString`. It affects production apps. ### Workaround: Is there a workaround for this issue? None. Users or app developers have little control over what the IME / services decide to do. The problematic code path in the engine directly interacts with system services so app developer can't workaround that. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? The PR description does not have repro steps. @p1318k could you add the steps to trigger the bug here? --- .../Source/FlutterTextInputPlugin.mm | 5 +- .../Source/FlutterTextInputPluginTest.mm | 75 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) 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 From 46485b19bbe33d117f8598e8ab7c4ed2d160f9eb Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:59:32 -0700 Subject: [PATCH 014/105] [CP-beta][ Tool ] Output DTD URI for Flutter web applications (#177321) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/176310 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `app.dtd` event is not emitted for Flutter web applications run with `--machine`. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Makes it impossible for tooling to connect to the DTD instance associated with a Flutter web application. This impacts the Flutter MCP extension. ### Workaround: Is there a workaround for this issue? No workaround available. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run a web application using `flutter run -d chrome --machine` and verify there's an `app.dtd` event once the application has started. --- .../flutter_tools/lib/src/isolated/resident_web_runner.dart | 2 +- .../test/general.shard/resident_web_runner_test.dart | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 52209aee4a628..796d383bb3ef4 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -934,7 +934,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/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 045a4b03efb49..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, @@ -2029,6 +2031,9 @@ class FakeDebugConnection extends Fake implements DebugConnection { @override late String devToolsUri; + @override + late String dtdUri; + final completer = Completer(); var didClose = false; From ea0f4435cf72022cb01396b0b30a5809d6069465 Mon Sep 17 00:00:00 2001 From: jesswrd Date: Tue, 28 Oct 2025 10:17:52 -0700 Subject: [PATCH 015/105] [CP-Beta] Bump Templates To Correct Versions (#177416) (#177608) This is a manual cherry pick of https://github.com/flutter/flutter/pull/177416 to beta. **Impacted Users (Approximately who will hit this issue, ex. all Flutter devs, Windows developers, all end-customers, apps using X framework feature).** Flutter devs who ship to Android. Template versions are changing. **Impact Description (What is the impact? ex. visual jank on Samsung phones, app crash, cannot ship an iOS app. Does it impact development? ex. flutter doctor crashes when Android Studio is installed. Or shipping a production app? ex. the app crashes on launch).** Affects flutter build to android. **Workaround (Is there a workaround for this issue?)** Use compatible depency versioning. **Risk (What is the risk level of this cherry-pick?)** Low **Test Coverage (Are you confident that your fix is well-tested by automated tests?)** Yes. Integration tests with new versioning have passed. **Validation Steps (What are the steps to validate that this fix works?)** Ran `flutter analyze --suggestions` and `flutter build apk` to verify versioning combination is valid. --- I bumped templates to the correct versions. I also included a fix for kgp and agp compatability. AGP 8.11.0 -> 8.11.1 Gradle 8.13 -> 8.14 KGP 2.2.0 -> 2.2.20 I ran `flutter analyze --suggestions` and `flutter build apk` to ensure these are safe versions. Will cherry pick this to beta after the pr merges. Fixes https://github.com/flutter/flutter/issues/177320 **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- ...android_java17_dependency_smoke_tests.dart | 4 +- .../android/buildscript-gradle.lockfile | 216 +++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../android/project-app.lockfile | 270 ++++++++++++------ .../android/project-integration_test.lockfile | 222 +++++++++----- .../android/settings.gradle | 4 +- .../android/buildscript-gradle.lockfile | 216 +++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../android/project-app.lockfile | 226 ++++++++++----- .../android/project-integration_test.lockfile | 222 +++++++++----- .../project-url_launcher_android.lockfile | 223 ++++++++++----- .../project-video_player_android.lockfile | 224 ++++++++++----- .../flutter_gallery/android/settings.gradle | 4 +- dev/tools/bin/generate_gradle_lockfiles.dart | 10 +- .../android/buildscript-gradle.lockfile | 216 +++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../hello_world/android/project-app.lockfile | 221 +++++++++----- .../hello_world/android/settings.gradle.kts | 4 +- .../flutter_tools/gradle/build.gradle.kts | 4 +- .../src/main/kotlin/plugins/PluginHandler.kt | 5 +- .../lib/src/android/gradle_utils.dart | 17 +- .../android/gradle_errors_test.dart | 2 +- .../android/gradle_utils_test.dart | 42 ++- .../test_data/plugin_project.dart | 4 +- 24 files changed, 1463 insertions(+), 899 deletions(-) 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/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/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/gradle/build.gradle.kts b/packages/flutter_tools/gradle/build.gradle.kts index e0265f532530c..31fc5cbaedc50 100644 --- a/packages/flutter_tools/gradle/build.gradle.kts +++ b/packages/flutter_tools/gradle/build.gradle.kts @@ -62,10 +62,10 @@ 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") 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/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/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/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index 33dc532022ba8..31d611f0f920c 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 @@ -1000,7 +1000,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' 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/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 { From 46b0f4eaedc0bf3f0af3123adc5c70b531b29cc6 Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:39:11 -0400 Subject: [PATCH 016/105] =?UTF-8?q?Revert=20"Resolve=20resolve=20native=20?= =?UTF-8?q?Flutter=20dependencies=20in=20Android=20Studio=E2=80=A6=20(#177?= =?UTF-8?q?605)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #177037 on 3.38 branch. This reverts commit 0c0406a6158eb07d28a70350a22801ee8f6870c9. Leaves `isInvokedFromAndroidStudio` --- .../gradle/src/main/kotlin/FlutterPlugin.kt | 43 +++++-------------- 1 file changed, 10 insertions(+), 33 deletions(-) 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") - } - } } From d74f2fc56ccb01b62c2bb40313c54c84673b7ddc Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:40:54 -0700 Subject: [PATCH 017/105] [CP-beta]Add guided error for precompiled cache error (#177607) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/176462 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Provides guided error message when building for iOS fails due to precompiled headers cache error. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) When using Xcode 26 and switching between branches or upgrading to new beta/stable, it throws an error due to headers of the Flutter framework changing. ### Workaround: Is there a workaround for this issue? Run `flutter clean` ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. git checkout 3.35.5 2. `flutter create my_app` 3. `flutter build ios` 4. git checkout main 5. `flutter build ios` (it should error) --- packages/flutter_tools/lib/src/ios/mac.dart | 20 ++++++++ .../test/general.shard/ios/mac_test.dart | 50 +++++++++++++++++++ 2 files changed, 70 insertions(+) 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/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', () { From f16b4ff8921f452da733f17b243f627d08f1e378 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:32:10 -0500 Subject: [PATCH 018/105] Update `engine.version` for 3.38.1 hotfix release (#177675) Updates the `engine.version` to the last commit to touch the engine: https://github.com/flutter/flutter/commit/d7ec7e8064d93a8d8bdd418103ec48cfafbc4841 Verified by the `flutter/bin/internal/last_engine_commit.sh` script. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4d1a932840446..665a14aa1fb2d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -060c2cc550a0b0d37aa48d40b5f1bb8984b7439a +d7ec7e8064d93a8d8bdd418103ec48cfafbc4841 From fd7f423ff3f2a9a513f764cac8d4471b2c57b890 Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Mon, 10 Nov 2025 10:09:11 -0800 Subject: [PATCH 019/105] [CP-Beta] Cherry-pick ninja+cmake deps (#178244) Pulls in #178054 and #178079 Please note there is one "bringup: true" in this change: bringup: true # Failing: #178060 --- .ci.yaml | 104 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 17 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 292b8c3534dca..6fa76ff7bc239 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" @@ -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 From 45eb4587f866895cddbab7711f97ba69df38cf87 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:03:24 -0600 Subject: [PATCH 020/105] Retry 3.38 release stamp (#178256) My take on https://github.com/flutter/flutter/pull/178178 **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- CHANGELOG.md | 6 ++++++ DEPS | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9ce38b8995d..2eea8dfe56a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,12 @@ More information and tips: docs/releases/Hotfix-Documentation-Best-Practices.md --> +## Flutter 3.38 Changes + +### [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..405c3053a3e66 100644 --- a/DEPS +++ b/DEPS @@ -56,15 +56,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': '4f9f04414cd2e6d36feeeed83f6c77835c35fdec', # 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', @@ -302,7 +302,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'), From db95cb7370d885eefd3626f3d1cba37a456095ff Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:10:06 -0800 Subject: [PATCH 021/105] [CP-beta][ Widget Preview ] Add analytic event that's reported when the previewer is opened (#177960) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/177948 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Add additional analytics for `flutter widget-preview start` ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Analytics collected for `flutter widget-preview start` won't give an accurate representation of usage as IDE plugins will start launching the widget previewer by default. This will result in `widget-preview` analytics effectively tracking the number of IDE users rather than actual usage of the widget previewer. ### Workaround: Is there a workaround for this issue? No ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? N/A --- .../lib/src/commands/widget_preview.dart | 1 + .../lib/src/widget_preview/analytics.dart | 12 ++++++++++++ .../lib/src/widget_preview/dtd_services.dart | 15 +++++++++++++++ .../test/dtd_services_test.dart | 19 ++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index d8cf24a3f3311..47b7515e457e5 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -250,6 +250,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C ); late var _dtdService = WidgetPreviewDtdServices( + previewAnalytics: previewAnalytics, fs: fs, logger: logger, shutdownHooks: shutdownHooks, 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/dtd_services.dart b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart index 64222a5048fd9..29959a9d612ec 100644 --- a/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart +++ b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart @@ -20,6 +20,7 @@ import '../base/process.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 +28,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 +54,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 +75,7 @@ class WidgetPreviewDtdServices { @visibleForTesting late final preferences = PersistentPreferences(fs: fs); + final WidgetPreviewAnalytics previewAnalytics; final FileSystem fs; final Logger logger; final ShutdownHooks shutdownHooks; @@ -109,7 +115,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) 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(), From aef5bdc7c2b85cb5a93be52ac35bc9a11df4b3cf Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:34:58 -0800 Subject: [PATCH 022/105] [CP-beta][web] Move webparagraph tests to their right location (#178304) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: N/A ### Changelog Description: Move the new font collection test to the correct folder. ### Impact Description: Flakiness in CI. ### Workaround: N/A ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: Notice there are no font collection-related failures in [`Linux linux_web_engine_tests`](https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20linux_web_engine_tests) --- .../web_paragraph => webparagraph}/font_collection_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename engine/src/flutter/lib/web_ui/test/{ui/web_paragraph => webparagraph}/font_collection_test.dart (98%) 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); From 5205556b411a652eb2aea2163ee6781ecbb8b645 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:53:20 -0800 Subject: [PATCH 023/105] [CP-beta][ Tool ] Add `Stream.transformWithCallSite` to provide more useful stack traces (#177994) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? Example issue: https://github.com/flutter/flutter/issues/81666 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Improve logging for UTF-8 decoding errors. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) When an exception is thrown within a transformer provided to `Stream.transform(...)`, an asynchronous stack trace pointing to the internal transformation machinery is reported instead of where the call to `transform(...)` was made, making tracking down where these exceptions come from extremely difficult. ### Workaround: Is there a workaround for this issue? No. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Not a fix, just additional logging. Tests have been added to ensure this extension works as expected. --- .../lib/src/android/android_device.dart | 9 +- .../lib/src/android/android_emulator.dart | 8 +- .../flutter_tools/lib/src/base/process.dart | 7 +- .../flutter_tools/lib/src/base/utils.dart | 24 ++ .../lib/src/commands/symbolize.dart | 8 +- packages/flutter_tools/lib/src/compile.dart | 14 +- .../flutter_tools/lib/src/dart/analysis.dart | 8 +- .../debug_adapters/flutter_base_adapter.dart | 5 +- .../flutter_tools/lib/src/desktop_device.dart | 4 +- .../lib/src/devtools_launcher.dart | 11 +- .../lib/src/ios/core_devices.dart | 7 +- .../flutter_tools/lib/src/ios/devices.dart | 10 +- .../flutter_tools/lib/src/ios/ios_deploy.dart | 303 +++++++++--------- packages/flutter_tools/lib/src/ios/lldb.dart | 8 +- .../flutter_tools/lib/src/ios/simulators.dart | 30 +- .../lib/src/ios/xcode_debug.dart | 51 ++- .../flutter_tools/lib/src/macos/xcdevice.dart | 7 +- .../lib/src/protocol_discovery.dart | 3 +- .../lib/src/test/flutter_tester_device.dart | 5 +- .../lib/src/test/test_golden_comparator.dart | 8 +- .../flutter_tools/lib/src/web/chrome.dart | 7 +- .../lib/src/widget_preview/dtd_services.dart | 3 +- .../test/general.shard/utils_test.dart | 47 +++ 23 files changed, 305 insertions(+), 282 deletions(-) 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/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/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/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_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/ios/core_devices.dart b/packages/flutter_tools/lib/src/ios/core_devices.dart index 8db15860a934d..6c734903ea970 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'; @@ -740,8 +741,7 @@ class IOSCoreDeviceControl { 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); @@ -755,8 +755,7 @@ class IOSCoreDeviceControl { }); final StreamSubscription stderrSubscription = launchProcess.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) + .transform(utf8LineDecoder) .listen((String line) { if (launchCompleter.isCompleted && !_ignoreLog(line)) { coreDeviceLogForwarder.addLog(line); diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 71c302ebffe9e..0921ec7c5860d 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -1697,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/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/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/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/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/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 3fe8b23c6f5f4..66933c61fef50 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'; @@ -303,7 +303,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 +313,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/dtd_services.dart b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart index 29959a9d612ec..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,6 +17,7 @@ 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'; @@ -190,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/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; + }); } From cb467e31a54207dc987aca5bb0941c4d2e3fd9ed Mon Sep 17 00:00:00 2001 From: Elijah Okoroh Date: Tue, 11 Nov 2025 11:15:58 -0800 Subject: [PATCH 024/105] [CP-beta] Update .ci.yaml in flutter/flutter to use 15.5 (#177939) (#178132) Update .ci.yaml in flutter/flutter to use 15.5 Note: (Not all devicelab bots are macOS 15.5. Some are 15.1 and 15.6.1) *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* Fixes #177394 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .ci.yaml | 24 ++++++------ engine/src/flutter/.ci.yaml | 8 ++-- .../ci/builders/linux_web_engine_test.json | 2 +- .../src/flutter/ci/builders/local_engine.json | 38 +++++++++---------- .../ci/builders/mac_android_aot_engine.json | 12 +++--- .../flutter/ci/builders/mac_clang_tidy.json | 14 +++---- .../flutter/ci/builders/mac_host_engine.json | 36 +++++++++--------- .../flutter/ci/builders/mac_ios_engine.json | 20 +++++----- engine/src/flutter/ci/builders/mac_unopt.json | 18 ++++----- .../lib/web_ui/dev/generate_builder_json.dart | 2 +- 10 files changed, 87 insertions(+), 87 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 6fa76ff7bc239..c68ff858a29db 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -166,7 +166,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5 device_type: none $flutter/osx_sdk : >- { @@ -183,7 +183,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5 device_type: none cpu: arm64 $flutter/osx_sdk : >- @@ -203,7 +203,7 @@ platform_properties: ] device_type: none mac_model: "Macmini8,1" - os: Mac-14|Mac-15 + os: Mac-15.5 tags: > ["devicelab", "hostonly", "mac"] $flutter/osx_sdk : >- @@ -221,7 +221,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-14|Mac-15 + os: Mac-15.5 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -240,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 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -256,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 cpu: x86 device_type: "mokey" @@ -267,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 cpu: arm64 device_type: "mokey" @@ -282,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 device_os: iOS-18 $flutter/osx_sdk : >- { @@ -300,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 cpu: x86 device_os: iOS-18 $flutter/osx_sdk : >- @@ -319,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 cpu: arm64 device_os: iOS-18 $flutter/osx_sdk : >- @@ -5562,7 +5562,7 @@ targets: tags: > ["devicelab", "ios", "mac"] task_name: ios_debug_workflow - os: Mac-15 + os: Mac-15.5 $flutter/osx_sdk : >- { "sdk_version": "17a5295f" @@ -5604,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", "cpu=x86"] - name: Mac_ios animated_blur_backdrop_filter_perf_ios__timeline_summary recipe: devicelab/devicelab_drone diff --git a/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 582d3312a843c..20bf75063ed6f 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 $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 - 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 - 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 - cpu=x86 - name: Linux windows_android_aot_engine 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..fde9e550d281a 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", "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..5ff009df2c515 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", "device_type=none" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -70,7 +70,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -103,7 +103,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -136,7 +136,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -170,7 +170,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -206,7 +206,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -370,7 +370,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -403,7 +403,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -436,7 +436,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -520,7 +520,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -604,7 +604,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -636,7 +636,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -669,7 +669,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -702,7 +702,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -841,7 +841,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -925,7 +925,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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" ], "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" ], "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..ead4cf8b61724 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", "cpu=x86" ], "gclient_variables": { @@ -83,7 +83,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -143,7 +143,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -203,7 +203,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -261,7 +261,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -321,7 +321,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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..cf497d3bc8b01 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", "cpu=arm64" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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", "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", "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", "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", "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", "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..5ed06bb692e69 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", "cpu=arm64" ], "gclient_variables": { @@ -84,7 +84,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -140,7 +140,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -205,7 +205,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -256,7 +256,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -307,7 +307,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -370,7 +370,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -424,7 +424,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -477,7 +477,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -543,7 +543,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -600,7 +600,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -656,7 +656,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -722,7 +722,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -777,7 +777,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -832,7 +832,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -899,7 +899,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -957,7 +957,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -1014,7 +1014,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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..934549e832b59 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", "cpu=arm64" ], "gclient_variables": { @@ -61,7 +61,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -110,7 +110,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -157,7 +157,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -204,7 +204,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -251,7 +251,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -300,7 +300,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -351,7 +351,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -449,7 +449,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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..5ee3c8503bc82 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", "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", "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", "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", "cpu=arm64" ], "gclient_variables": { @@ -216,7 +216,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -275,7 +275,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "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", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -468,7 +468,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14|Mac-15", + "os=Mac-15.5", "cpu=arm64" ], "gclient_variables": { 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..153b4cbbd0fa2 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', cpu: 'arm64', ), ]; From a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:00:09 -0600 Subject: [PATCH 025/105] Update `engine.version` for 3.38 stable release (#178324) To last commit merged, which was when the engine was last updated: https://github.com/flutter/flutter/commit/cb467e31a54207dc987aca5bb0941c4d2e3fd9ed **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 665a14aa1fb2d..8bcf0c92f4878 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d7ec7e8064d93a8d8bdd418103ec48cfafbc4841 +cb467e31a54207dc987aca5bb0941c4d2e3fd9ed From ff219d675fc81e9ad730d4ccc2f2f3d83e8be92a Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:42:36 -0800 Subject: [PATCH 026/105] [CP-beta]fix: infra out of resources (#178392) Flutter devicelab infrastructure was updated to 15.7 for x86 macs; required to test anything on dashboard: https://github.com/flutter/flutter/issues/178384 --- .ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index c68ff858a29db..67a42a643d5ec 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -256,7 +256,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-15.1|Mac-15.5|Mac-15.6 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: x86 device_type: "mokey" From b5990e5ccc5e325fd24f0746e7d6689bbebc7c65 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:08:24 -0600 Subject: [PATCH 027/105] Update DEPS with stable dart version (#178401) .. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 405c3053a3e66..7b31ad315d86c 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,7 @@ 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': '4f9f04414cd2e6d36feeeed83f6c77835c35fdec', + 'dart_revision': 'b1a587b650acd12239743dd1f9d88d6fe19ae442', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From b45fa18946ecc2d9b4009952c636ba7e2ffbb787 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 12 Nov 2025 22:09:06 -0600 Subject: [PATCH 028/105] Bump `engine.version` (#178430) Looks like DEPS changes require this bump. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8bcf0c92f4878..1b1c028856949 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cb467e31a54207dc987aca5bb0941c4d2e3fd9ed +b5990e5ccc5e325fd24f0746e7d6689bbebc7c65 From ad76f2b4ab8508a05c5df3baa7dcf4553751e33b Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:23:26 -0600 Subject: [PATCH 029/105] Add 3.38.1 release notes (#178493) Retroactively adding this note. Sadly these will be release in the next hotfix, but they will be available on master once https://github.com/flutter/flutter/pull/178487 lands. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eea8dfe56a4f..8f10c5ced487d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. From 5c041457d2c274778832acc28bb39a2032553cc2 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:21:13 -0800 Subject: [PATCH 030/105] [CP-stable][ Widget Preview ] Gracefully handle unexpected analysis context disposal (#178646) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178472 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples - [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. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Unnecessary noise in our crash reporting. Shouldn't have a noticeable impact on development experience. ### Workaround: Is there a workaround for this issue? No. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Run `flutter widget-preview start` in a Flutter project 2. Edit a source file and immediately send SIGQUIT to the `flutter` process 3. Repeat this process multiple times to verify no error is reported --- .../src/widget_preview/dependency_graph.dart | 13 +- .../src/widget_preview/preview_detector.dart | 134 ++++++++++-------- .../lib/src/widget_preview/utils.dart | 6 + ...eview_detector_regression_178472_test.dart | 99 +++++++++++++ 4 files changed, 189 insertions(+), 63 deletions(-) create mode 100644 packages/flutter_tools/test/commands.shard/permeable/widget_preview/preview_detector_regression_178472_test.dart 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/preview_detector.dart b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart index 65ae5b186bc35..823985de7126d 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart @@ -53,7 +53,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 +69,36 @@ 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(); - // Wait for file watcher to finish initializing, otherwise we might miss changes and cause - // tests to flake. - await watcher.ready; - return _dependencyGraph; + 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; + }); } Future dispose() async { @@ -105,7 +108,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,7 +118,7 @@ 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; // If the pubspec has changed, new dependencies or assets could have been added, requiring // the preview scaffold's pubspec to be updated. @@ -146,7 +149,13 @@ class PreviewDetector { 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 +165,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 +182,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 +216,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 +233,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 +286,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/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/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..20e8f5d183910 --- /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( + projectRoot: project.directory, + 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(), + ), + ), + 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(); +} From 95324c157e119b224f1462faa013f670768627a3 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:26:53 -0800 Subject: [PATCH 031/105] [CP-stable]Allow empty dart defines in `flutter assemble` (#178542) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178452 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Flutter fails to build on iOS with error message: "Improperly formatted define flag" in add-to-app scenarios ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Impacts development: Add-to-app apps fails to build / xcode archive fails ### Workaround: Is there a workaround for this issue? Yes, users can patch the flutter_tool code and apply the change locally. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? The issue can be reproduced / verified by building [flutter/samples@main/add_to_app/multiple_flutters](https://github.com/flutter/samples/tree/main/add_to_app/multiple_flutters). Some users have reported that the fix [worked for them](https://github.com/flutter/flutter/issues/178452#issuecomment-3531294620) --- .../lib/src/commands/assemble.dart | 6 ++-- .../lib/src/runner/flutter_command.dart | 5 +++- .../hermetic/assemble_test.dart | 29 +++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) 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/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/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 { From b8a7a92a10db03b5356c8d47cbae9750c6e9faf3 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:30:04 -0800 Subject: [PATCH 032/105] [CP-stable][ Widget Preview ] Throw `ToolExit` if Flutter Web is not enabled (#178534) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178486 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping of production apps (the app crashes on launch). This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick. Running `flutter widget-preview start` with Flutter web disabled will result in an error message stating that either Chrome couldn't be found or a `StateError` is thrown (for `--web-server`). ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. [flutter/178486] When running `flutter widget-preview start` with Flutter Web disabled, an exception is thrown and the widget previewer fails to start. ### Workaround: Is there a workaround for this issue? Run `flutter config --enable-web`, but there's currently no indication that this needs to be done. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Run `flutter config --no-enable-web` 2. Run `flutter widget-preview start` in a Flutter project 3. Verify an error message with instructions to enable Flutter web is output --- .../lib/src/commands/widget_preview.dart | 9 ++++++ .../widget_preview/widget_preview_test.dart | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index 47b7515e457e5..4c32dd8aa702b 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'; @@ -389,6 +390,14 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C 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; 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..ea5df714eddbb 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'; @@ -265,6 +266,37 @@ 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( From 7e4b2a449dd71605919182d3d5e7fa6fec531460 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:31:58 -0800 Subject: [PATCH 033/105] [CP-stable][ Widget Preview ] Ignore modifications to files in ephemeral directories (#178497) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178317 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Running `flutter pub get` can crash the widget previewer when plugin dependencies are added or updated. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The widget previewer can crash when `flutter pub get` is run and causes plugins to be updated or added to the project. IDEs regularly run `flutter pub get` and automatically start up the widget previewer, making this the top tool crasher for 3.38. Also, when an IDE-managed widget previewer crashes, it silently dies without any indication to the user as the preview environment continues to work but will no longer hot reload when the user makes changes to their sources. ### Workaround: Is there a workaround for this issue? 1. Run `flutter pub get` 2. Start / restart the IDE ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Run `flutter widget-preview start` in a Flutter project 2. Add a plugin dependency to the project's `pubspec.yaml` 3. Run `flutter pub get` in the project, which should not cause the `flutter widget-preview start` process to crash --- .../lib/src/commands/widget_preview.dart | 2 +- packages/flutter_tools/lib/src/project.dart | 16 +++ .../src/widget_preview/preview_detector.dart | 26 ++++- .../preview_code_generator_test.dart | 2 +- ...eview_detector_regression_173895_test.dart | 6 +- ...eview_detector_regression_178317_test.dart | 97 +++++++++++++++++++ .../utils/preview_detector_test_utils.dart | 5 +- 7 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_178317_test.dart diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index 4c32dd8aa702b..a73d77f6c10cd 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -235,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, diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 40eee32063cdc..6973aebb33bb0 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'; @@ -238,6 +240,20 @@ 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, + 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'); 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 823985de7126d..bf9dde46f6a31 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; @@ -120,15 +122,30 @@ class PreviewDetector { // in use when we call context.changeFile(...). 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; } @@ -146,7 +163,6 @@ 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; 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..3242940023c19 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,7 +239,7 @@ void main() { fakeFlutterVersion: FakeFlutterVersion(), ), ), - projectRoot: projectDir, + project: project, fs: fs, logger: logger, onChangeDetected: (_) {}, 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..be853f24f6c4b --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector/preview_detector_regression_178317_test.dart @@ -0,0 +1,97 @@ +// 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 { + 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/utils/preview_detector_test_utils.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart index 5fc58bd4aadcb..b3bfda51d23f3 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,6 +10,7 @@ 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/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'; @@ -49,6 +50,8 @@ PreviewDetector createTestPreviewDetector() { throw StateError('$initializeTestPreviewDetectorState was not called!'); } _projectRoot = _fs.systemTempDirectory.createTempSync('root'); + final FlutterProject project = FlutterProject.fromDirectoryTest(_projectRoot!); + return PreviewDetector( platform: FakePlatform(), previewAnalytics: WidgetPreviewAnalytics( @@ -59,7 +62,7 @@ PreviewDetector createTestPreviewDetector() { fs: MemoryFileSystem.test(), ), ), - projectRoot: _projectRoot!, + project: project, logger: BufferLogger.test(), fs: _fs, onChangeDetected: _onChangeDetectedRoot, From 444b8c33ed8f15476de425c75903661146c6feb9 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:35:05 -0800 Subject: [PATCH 034/105] [CP-stable]Add support for Visual Studio 2026 (#178450) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/176399 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Visual Studio 2026 is not supported when compiling Windows desktop applications. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Developers that only have Visual Studio 2026 installed are unable to compile Windows applications. ### Workaround: Is there a workaround for this issue? Install an older version of Visual Studio. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Install Visual Studio 2026 on a Windows installation without any other Visual Studio versions installed. 2. Run `flutter run -d windows` to run a Windows desktop application. 3. The application should successfully build and run. --- .../lib/src/windows/visual_studio.dart | 1 + .../windows/visual_studio_test.dart | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) 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/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; From 06f9b6ac8a2f3b55ff77b36d77513fce13ad36fd Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:56:37 -0800 Subject: [PATCH 035/105] [CP-stable][ Widget Preview ] Don't require 'flutter pub get' to be run in the root project (#178394) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178052 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples The widget previewer fails to start if `flutter pub get` has not been run in the target project. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The widget previewer will fail to launch. For CLI users, the error message stating that the command needs to be run within a Flutter project is misleading. For IDE users, they may get a dialog stating the widget previewer failed to start with no actionable feedback. ### Workaround: Is there a workaround for this issue? Run `flutter pub get` in the project and then restart the widget previewer, either by relaunching the IDE or re-running `flutter widget-preview start`. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Delete `.dart_tool/` from a Flutter project. 2. Run `flutter widget-preview start` within that project. 3. The widget previewer should start successfully. --- .../lib/src/commands/widget_preview.dart | 4 +-- .../widget_preview/widget_preview_test.dart | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index a73d77f6c10cd..30bcbabcdd4b0 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -112,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; @@ -281,7 +281,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) { 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 ea5df714eddbb..06156cf0b857d 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 @@ -299,6 +299,31 @@ void main() { ); }); + 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 { From b47385635c3db3a0cd5dd19292f284beaec1e3db Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 12:17:27 -0800 Subject: [PATCH 036/105] [CP-stable][ Tool ] Only process a single unhandled tool exception (#178469) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178318 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Certain `flutter` crash scenarios can result in multiple crash reports being submitted for a single process crash. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Crash analytics data can be skewed to make certain bugs appear much more severe then they actually are. ### Workaround: Is there a workaround for this issue? Don't crash? :) ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run attached unit test. --- packages/flutter_tools/lib/runner.dart | 34 +++++++ .../general.shard/runner/runner_test.dart | 90 +++++++++++++++++++ 2 files changed, 124 insertions(+) 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/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 => ''; From 2ca3bb88e4f50c079877a1a6082154d9abbb71fc Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Mon, 17 Nov 2025 12:35:26 -0800 Subject: [PATCH 037/105] [CP-stable]Roll dartdoc to 9.0.0 (#178638) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? < Replace with issue link here > https://github.com/flutter/flutter/issues/178639 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Classes marked with `@Deprecated.implement` should not be crossed out. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Confusing dartdoc rendering on https://api.flutter.dev ### Workaround: Is there a workaround for this issue? N/A ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? N/A --- dev/bots/docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 83115711c29eb0b8b6c921ff55b113b089f025c0 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 17 Nov 2025 17:13:02 -0500 Subject: [PATCH 038/105] Fix analysis error due to incorrect arguments (#178679) Fixes https://github.com/flutter/flutter/issues/178677 --- .../widget_preview/preview_detector_regression_178472_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 20e8f5d183910..37253f1601d0e 100644 --- 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 @@ -33,7 +33,6 @@ void main() { logger = BufferLogger.test(); project = FlutterProject.fromDirectoryTest(fs.systemTempDirectory.createTempSync('root')); previewDetector = PreviewDetector( - projectRoot: project.directory, platform: FakePlatform(), previewAnalytics: WidgetPreviewAnalytics( analytics: getInitializedFakeAnalyticsInstance( @@ -43,6 +42,7 @@ void main() { fs: MemoryFileSystem.test(), ), ), + project: project, logger: logger, fs: fs, onChangeDetected: (_) {}, From a7cb63e342e0d62b529dad4eeb05bc53d9267da9 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 18 Nov 2025 06:05:22 -0800 Subject: [PATCH 039/105] [CP-stable]Check for devicectl launch logs from std and file (#178675) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178421 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Fixes an issue where debugging from an IDE hangs when using a physical iOS 26 device. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) When debugging from an IDE with a physical iOS 26 device, it installs and app but hangs on a white screen during launching. ### Workaround: Is there a workaround for this issue? Use a simulator or use release mode ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Create an app Use an IDE (like VS Code) to debug the app on an iOS 26 physical device --- .../lib/src/ios/core_devices.dart | 44 +++++++++++++-- .../general.shard/ios/core_devices_test.dart | 56 +++++++++++++++++++ 2 files changed, 94 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/core_devices.dart b/packages/flutter_tools/lib/src/ios/core_devices.dart index 6c734903ea970..6d9314ecd38b9 100644 --- a/packages/flutter_tools/lib/src/ios/core_devices.dart +++ b/packages/flutter_tools/lib/src/ios/core_devices.dart @@ -335,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. @@ -623,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(), @@ -647,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, ]; @@ -676,7 +687,7 @@ class IOSCoreDeviceControl { deviceId: deviceId, launchArguments: launchArguments, startStopped: startStopped, - outputFile: output, + jsonOutputFile: output, ); try { @@ -727,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, @@ -734,8 +748,9 @@ class IOSCoreDeviceControl { launchArguments: launchArguments, startStopped: startStopped, attachToConsole: true, + logOutputFile: output, ); - + Timer? timer; try { final Process launchProcess = await _processUtils.start(command); coreDeviceLogForwarder.launchProcess = launchProcess; @@ -749,7 +764,7 @@ class IOSCoreDeviceControl { _logger.printTrace(line); } - if (line.contains('Waiting for the application to terminate')) { + if (!launchCompleter.isCompleted && line.contains(kCoreDeviceLaunchCompleteLog)) { launchCompleter.complete(true); } }); @@ -778,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/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', () { From f5a8537f90d143abd5bb2f658fa69c388da9677b Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:27:21 -0500 Subject: [PATCH 040/105] Update changelog with 3.38.2 cherrypicks (#178674) https://github.com/flutter/flutter/commits/flutter-3.38-candidate.0?since=2025-11-14&until=2025-11-17 --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f10c5ced487d..9b4305230ce3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,17 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. From 13e658725ddaa270601426d1485636157e38c34c Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:19:23 -0500 Subject: [PATCH 041/105] Bump dart to 3.10.1 (#178869) * Part 1/2 to fix https://github.com/flutter/flutter/issues/178772 * Fixes https://github.com/flutter/flutter/issues/178804 --- CHANGELOG.md | 5 +++++ DEPS | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4305230ce3c..5aab58be38a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,11 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. diff --git a/DEPS b/DEPS index 7b31ad315d86c..92cb7ca545b74 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,7 @@ 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': 'b1a587b650acd12239743dd1f9d88d6fe19ae442', + 'dart_revision': '13d929085afa86e5902ed7293cca8509f099ee97', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -314,7 +314,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'), From 19074d12f7eaf6a8180cd4036a430c1d76de904e Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:53:13 -0500 Subject: [PATCH 042/105] 3.38.3 bump engine sha (#178884) part 2/2 of #178772 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1b1c028856949..582430af7d18b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b5990e5ccc5e325fd24f0746e7d6689bbebc7c65 +13e658725ddaa270601426d1485636157e38c34c From fc0b86a61ee7def106a6e8706d2030b87af6209f Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:59:27 -0800 Subject: [PATCH 043/105] [CP-stable]Restore OpenGL state modified by fl_compositor_opengl_present_layers (#178937) ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178547 ### Changelog Description: This PR fixes rendering errors in the Linux desktop embedder when using Skia. The embedder may overwrite OpenGL state that Skia assumes is unmodified. ### Impact Description: Bad rendering in Linux desktop apps. ### Workaround: Use Impeller instead of Skia on Linux. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: Run the example app in https://github.com/flutter/flutter/issues/178547 on Linux --- .../platform/linux/fl_compositor_opengl.cc | 35 ++++++++++++++++--- .../linux/fl_compositor_opengl_test.cc | 4 +++ .../platform/linux/testing/mock_epoxy.cc | 32 +++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) 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/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; From cf258ba2c7cd5c190948c04ab7d422337bed57c5 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:03:09 -0800 Subject: [PATCH 044/105] [CP-stable][ Tool ] Use a separate output directory when the native hooks run the build system (#179016) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178529 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping of production apps (the app crashes on launch). This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick. Running `flutter run -d chrome` on a project with localization generation, the generated localizations classes are deleted immediately. ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. When running `flutter run -d chrome` on projects with localizations, generated localizations sources are deleted on first run. ### Workaround: Is there a workaround for this issue? 1) Run `flutter run -d chrome`, which will fail due to the generated localizations code being deleted 2) Run `flutter run -d chrome` again, which will only rebuild the generated localizations code without rerunning the native hooks build step. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run `flutter run -d chrome` in a project with localizations, ensure it actually starts. --- .../lib/src/build_system/build_system.dart | 22 ++++++++ .../targets/hook_runner_native.dart | 19 ++++++- .../targets/hook_runner_native_test.dart | 55 +++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 packages/flutter_tools/test/general.shard/build_system/targets/hook_runner_native_test.dart 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/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/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, + ); + }), + }, + ); +} From aa5986c4ee55db730da03f10bdfea74778cd832b Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:12:55 -0800 Subject: [PATCH 045/105] [CP-stable][ Widget Preview ] Fix crash when `widget_preview_scaffold/.dart_tool` doesn't exist (#179042) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/178660 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `flutter widget-preview start` can crash if `.dart_tool/widget_preview_scaffold/.dart_tool` doesn't exist on subsequent runs. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) If the `.dart_tool/widget_preview_scaffold/.dart_tool/` directory wasn't created during the initial run of `flutter widget-preview start` due to the command being interrupted or pub being disabled, `flutter widget-preview start` would crash due to the `package_config.json` logic walking up the directory structure looking for the nearest `package_config.json`. This would point to the parent project's `package_config.json`, which would not be compatible with the widget preview scaffold project. ### Workaround: Is there a workaround for this issue? Manually running `flutter pub get` in `.dart_tool/widget_preview_scaffold/`. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1) Run `flutter widget-preview start` and close it once the previewer opens 2) Delete `.dart_tool/widget_preview_scaffold/.dart_tool` 3) Run `flutter widget-preview start` and verify the previewer opens --- .../lib/src/commands/widget_preview.dart | 11 +++++-- .../preview_pubspec_builder.dart | 17 ++++++---- .../widget_preview_test.dart | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index 30bcbabcdd4b0..36d9f3e77c915 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -318,8 +318,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, ); @@ -333,6 +334,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(); @@ -343,7 +350,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); 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..235457e99d2ab 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 @@ -90,6 +90,8 @@ class PreviewPubspecBuilder { ); } + PubOutputMode get _outputMode => verbose ? PubOutputMode.all : PubOutputMode.failuresOnly; + Future populatePreviewPubspec({ required FlutterProject rootProject, String? updatedPubspecPath, @@ -125,7 +127,6 @@ class PreviewPubspecBuilder { }), }; - final PubOutputMode outputMode = verbose ? PubOutputMode.all : PubOutputMode.failuresOnly; await pub.interactively( [ pubAdd, @@ -145,7 +146,7 @@ class PreviewPubspecBuilder { context: PubContext.pubAdd, command: pubAdd, touchesPackageConfig: true, - outputMode: outputMode, + outputMode: _outputMode, ); // Adds dependencies required by the widget preview scaffolding. @@ -160,18 +161,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/test/integration.shard/widget_preview_test.dart b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart index ef75a4da21ef2..886342fbfb1c7 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'; @@ -125,6 +126,36 @@ void main() { await runWidgetPreview(expectedMessages: firstLaunchMessagesWebServer, useWebServer: true); }); + 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); + }); + 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); From bfd0db617a84682cf2abd6d229bf9b501ad94946 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:29:51 -0800 Subject: [PATCH 046/105] [CP-stable][ Tool ] Remove --no-sandbox when launching web apps on Chrome device (#179192) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/175227 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Flutter Web applications launched in Chrome show a warning related to `--no-sandbox`. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) We were incorrectly disabling the Chrome sandbox for non-test contexts, which results in a ominous warning about "Stability and security [suffering]". ### Workaround: Is there a workaround for this issue? N/A ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run `flutter run -d chrome`, verify the launched Chrome instance doesn't have a warning banner. --- packages/flutter_tools/lib/src/web/chrome.dart | 8 ++++++-- .../integration.shard/isolated/dart_data_asset_test.dart | 5 ++++- packages/flutter_tools/test/web.shard/chrome_test.dart | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 66933c61fef50..df13a37c65349 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -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, ]; 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/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', From 79e60d735d0f16935671e4185de5a740895c1dcc Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:42:29 -0800 Subject: [PATCH 047/105] [CP-stable][ Widget Preview ] Handle changes to unexpected pubspec.yaml files gracefully (#179198) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/179155 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `flutter widget-preview start` crashes if a file named `pubspec.yaml` is modified outside the root of the previewed project. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The widget previewer can silently crash in the context of an IDE if a developer makes a change to a `pubspec.yaml` that's not the one for the previewed project (i.e., under `example/`). ### Workaround: Is there a workaround for this issue? N/A ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1) Run `flutter widget-preview start` 2) Create a new `pubspec.yaml` in a new `example/` folder and verify the tool doesn't crash --- packages/flutter_tools/lib/src/project.dart | 12 ++ .../src/widget_preview/preview_detector.dart | 5 + .../src/widget_preview/preview_manifest.dart | 85 ++++++++--- ...tor_invalid_preview_applications_test.dart | 22 ++- ...tector_previews_non_const_params_test.dart | 22 ++- .../preview_detector_test.dart | 55 ++++---- .../preview_detector_workspace_test.dart | 71 +++++----- .../preview_detector_graph_test.dart | 105 +++++++------- .../preview_manifest_test.dart | 5 +- .../preview_manifest_workspace_test.dart | 133 ++++++++++++++++++ .../utils/preview_detector_test_utils.dart | 43 +++++- .../widget_preview/utils/preview_project.dart | 39 +++-- 12 files changed, 427 insertions(+), 170 deletions(-) rename packages/flutter_tools/test/{general.shard/widget_preview => commands.shard/hermetic/widget_preview/preview_manifest}/preview_manifest_test.dart (97%) create mode 100644 packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_manifest/preview_manifest_workspace_test.dart diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 6973aebb33bb0..e71c5b27367d2 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -329,6 +329,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/widget_preview/preview_detector.dart b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart index bf9dde46f6a31..42c4be73f5d7c 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart @@ -99,6 +99,11 @@ class PreviewDetector { // 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; }); } 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/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_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/utils/preview_detector_test_utils.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/utils/preview_detector_test_utils.dart index b3bfda51d23f3..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,12 +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'; @@ -25,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. @@ -45,12 +50,36 @@ 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.fromDirectoryTest(_projectRoot!); + final FlutterProject project = FlutterProject.fromDirectory(_projectRoot!); return PreviewDetector( platform: FakePlatform(), @@ -70,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', From 4f0202555c9226c71ecb730ab43c2add69fb88c4 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 2 Dec 2025 13:56:37 -0500 Subject: [PATCH 048/105] [CP-stable][ Tool ] Don't try to reattach when attach target disappears (#179193) (#179291) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/156692 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `flutter attach` can crash if the target application disconnects unexpectedly. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The `flutter attach` process could crash when trying to attach to a new target after the initial target disappeared unexpectedly. This could result in an error popup in IDEs or an obvious crash on the CLI. This is a top-10 crasher for the tool. ### Workaround: Is there a workaround for this issue? N/A ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1) Run `flutter run` to deploy to an Android or iOS device. 2) Run `flutter attach` to connect to the running application. 3) Kill the running application by pressing `q` in the `flutter run` terminal. 4) The `flutter attach` process should simply exit with no crash. --- .../lib/src/commands/attach.dart | 317 ++++++++---------- .../flutter_tools/lib/src/commands/run.dart | 2 +- .../lib/src/resident_runner.dart | 4 +- .../commands.shard/hermetic/attach_test.dart | 57 ++++ .../general.shard/resident_runner_test.dart | 2 +- .../general.shard/terminal_handler_test.dart | 8 +- 6 files changed, 207 insertions(+), 183 deletions(-) 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/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index d4837c2d5aa31..fb4b29f805f94 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -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/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/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/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 { From b8f3374f2c048a06b7dd8a07e03e6b105de05d4b Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:00:56 -0800 Subject: [PATCH 049/105] [CP-stable][ Widget Preview ] Ignore changes under `ios/.symlinks` (#179300) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/179008 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `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. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The widget previewer's file watcher can detect `pubspec.yaml` changes within plugin packages that are reachable via a symlink. This can cause numerous `flutter pub get` requests to be issued that aren't necessary and can possibly cause a user's machine to hang. ### Workaround: Is there a workaround for this issue? No. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Run `flutter widget-preview start` on a Mac 2. Add a Flutter plugin with iOS support to the project 3. Run `flutter pub get` and verify that dozens of Dart processes aren't spawned --- packages/flutter_tools/lib/src/project.dart | 1 + .../preview_detector_regression_178317_test.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index e71c5b27367d2..1c1605eb98d74 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -249,6 +249,7 @@ class FlutterProject { android.ephemeralDirectory, ios.ephemeralDirectory, ios.ephemeralModuleDirectory, + ios.symlinks, linux.ephemeralDirectory, macos.ephemeralDirectory, windows.ephemeralDirectory, 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 index be853f24f6c4b..fad1645ccc487 100644 --- 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 @@ -66,6 +66,7 @@ void main() { } 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) { From 3ddc40e0b7a2781a3432219574238bd2a23002ff Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Tue, 2 Dec 2025 20:05:22 +0100 Subject: [PATCH 050/105] [CP-stable] Build hooks: Don't require toolchain for unit tests (#179214) ### Issue Link: https://github.com/flutter/flutter/pull/178954 (beta CP: https://github.com/flutter/flutter/pull/179211) ### Impact Description: Running `flutter test` on Linux or MacOS which does not have a `clang` starts failing on projects that target only Android otherwise (and do not require a Linux or MacOS toolchain) when there are build hooks anywhere in the dependencies. This PR changes the behavior for `flutter test` to only pass `clang` and friends if they are installed. This means that _if_ a Linux/MacOS toolchain is installed on the system, it will be used for both `flutter run -d Linux`/`MacOS` and `flutter test` (so that the same native compiler is used), but if it's not installed on the system both `flutter run -d AndroidDevice` and `flutter test` run successfully. This means end users don't have to go modify their systems/CIs to install Linux/MacOS toolchains for Android projects. ### Changelog Description: [flutter/178954] Fixes running `flutter test` on Linux/MacOS for Android projects with build hooks without the desktop native tooling installed. ### Workaround: All end users have to install `clang` and `ldd` on Linux/MacOS hosts and CI bots. ### Risk: What is the risk level of this cherry-pick? It changes the flow in Flutter tools from throwing an error to returning a nullable value. ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: On a Linux and MacOS system, make a Flutter app that only targets Android. Add a build hook. And ensure there's no `clang` on the `PATH` (Can be verified by `flutter doctor -v` finding no tooling for Flutter desktop). Run `flutter test` and it shouldn't fail due to `clang` not being installed. For MacOS, XCode needs to not be installed. --- .../native_assets/linux/native_assets.dart | 59 +++++++++++---- .../macos/native_assets_host.dart | 39 ++++++---- .../src/isolated/native_assets/targets.dart | 33 ++++++-- .../isolated/linux/native_assets_test.dart | 26 ++++++- .../isolated/macos/native_assets_test.dart | 75 ++++++++++++++++--- .../isolated/native_assets_test.dart | 61 +++++++++++++++ 6 files changed, 244 insertions(+), 49 deletions(-) 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/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; + } } From 1a5911b54060313555bec81e3adf7e269bd89901 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 2 Dec 2025 18:27:51 -0500 Subject: [PATCH 051/105] [CP-stable][ Widget Preview ] Always generate scaffold under `$TMP` (#179039) (#179050) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/175058 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `flutter widget-preview start` can crash if `flutter clean` is run while the widget previewer is running. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) The widget previewer can silently crash in IDEs if the user runs `flutter clean` on the project. There's no indication that the previewer has crashed other than the fact that the previewer no longer hot reloads when the user make changes to their previews. ### Workaround: Is there a workaround for this issue? Not running `flutter clean` while the widget previewer is running, or restarting the IDE after `flutter clean` is run. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1) Run `flutter widget-preview start` 2) Run `flutter clean` and verify the `flutter widget-preview start` process doesn't crash. --- .../lib/src/commands/widget_preview.dart | 19 ++- .../lib/src/isolated/resident_web_runner.dart | 2 + packages/flutter_tools/lib/src/project.dart | 5 +- .../lib/src/resident_runner.dart | 2 +- .../preview_pubspec_builder.dart | 16 ++- .../lib/src/dtd/dtd_services.dart.tmpl | 2 +- .../src/widget_preview_rendering.dart.tmpl | 20 +-- .../preview_pubspec_builder_test.dart | 7 +- .../widget_preview/regress_176018_test.dart | 6 +- .../widget_preview/widget_preview_test.dart | 29 ++-- .../widget_preview_test.dart | 127 +++++++++++++----- .../lib/src/dtd/dtd_services.dart | 2 +- .../lib/src/widget_preview_rendering.dart | 20 +-- 13 files changed, 163 insertions(+), 94 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index 36d9f3e77c915..8b7aa432109f9 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -263,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); @@ -272,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; @@ -498,6 +506,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/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index 796d383bb3ef4..e0877fb52e74a 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -96,6 +96,7 @@ class ResidentWebRunner extends ResidentRunner { String? target, bool stayResident = true, bool machine = false, + String? projectRootPath, required this.flutterProject, required DebuggingOptions debuggingOptions, required FileSystem fileSystem, @@ -125,6 +126,7 @@ class ResidentWebRunner extends ResidentRunner { outputPreferences: outputPreferences, ), dartBuilder: hookRunner, + projectRootPath: projectRootPath, ); final FileSystem _fileSystem; diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 1c1605eb98d74..4dacd644873d4 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -231,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 diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index fb4b29f805f94..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: { 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 235457e99d2ab..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. @@ -120,8 +123,7 @@ 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, ), }), 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..96ee89a1f4b28 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,8 +6,8 @@ import 'dart:async'; import 'package:dtd/dtd.dart'; import 'package:json_rpc_2/json_rpc_2.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 { 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/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/permeable/widget_preview/widget_preview_test.dart b/packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart index 06156cf0b857d..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 @@ -150,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( @@ -211,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; } @@ -404,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(); }, @@ -438,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/integration.shard/widget_preview_test.dart b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart index 886342fbfb1c7..98f0be0ad60da 100644 --- a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart +++ b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart @@ -117,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); @@ -126,43 +130,53 @@ void main() { await runWidgetPreview(expectedMessages: firstLaunchMessagesWebServer, useWebServer: true); }); - 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); - }); + 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); + }, + // Project is always regenerated. + skip: true, // See https://github.com/flutter/flutter/issues/179036. + ); - // We shouldn't regenerate the scaffold after the initial run. - await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb); - }); + 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( @@ -212,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/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..96ee89a1f4b28 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,8 +6,8 @@ import 'dart:async'; import 'package:dtd/dtd.dart'; import 'package:json_rpc_2/json_rpc_2.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 { 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). From a5cb96369ef86c7e85abf5d662a1ca5d89775053 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 3 Dec 2025 12:56:06 -0800 Subject: [PATCH 052/105] Bump Dart version to 3.10.3 for Flutter 3.38.4 (#179373) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 92cb7ca545b74..efe14d6527819 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,7 @@ 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': '13d929085afa86e5902ed7293cca8509f099ee97', + 'dart_revision': '55d746718c14bd0a82147d1b5e2de5a5f22b1d5e', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 7ddf02de840a407a06ed72cc6a10d3e1ae4c8688 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 3 Dec 2025 13:02:32 -0800 Subject: [PATCH 053/105] Add changelog for flutter 3.38.4 (#179420) --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aab58be38a8c..daa94e5bb233f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,17 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. From 66dd93f9a27ffe2a9bfc8297506ce066ff51265f Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 3 Dec 2025 14:56:10 -0800 Subject: [PATCH 054/105] Bump engine version for Flutter 3.38.4 stable hotfix. (#179424) --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 582430af7d18b..94d7783fbcd59 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -13e658725ddaa270601426d1485636157e38c34c +a5cb96369ef86c7e85abf5d662a1ca5d89775053 From 1527ae0ec577a4ef50e65f6fefcfc1326707d9bf Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Thu, 11 Dec 2025 10:04:31 -0500 Subject: [PATCH 055/105] Update flutter 3.38 to use dart 3.10.4 (#179701) - **Update dart version to 3.10.4** --- CHANGELOG.md | 4 ++++ DEPS | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daa94e5bb233f..78acf13c2568c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. diff --git a/DEPS b/DEPS index efe14d6527819..d0d0743f1efb0 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,7 @@ 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': '55d746718c14bd0a82147d1b5e2de5a5f22b1d5e', + 'dart_revision': 'a0daa5004ec02c0638ba6e50791ba9338a87374c', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From f6ff1529fd6d8af5f706051d9251ac9231c83407 Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Thu, 11 Dec 2025 11:50:07 -0500 Subject: [PATCH 056/105] Bump engine version for 3.38.5 (#179743) with bin/internal/last_engine_commit.sh > bin/internal/engine.version --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 94d7783fbcd59..f0eb004794088 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a5cb96369ef86c7e85abf5d662a1ca5d89775053 +1527ae0ec577a4ef50e65f6fefcfc1326707d9bf From 8ea0615e67b0fd5e2eb3e9549d5a8e9b04e26d17 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:03:58 -0800 Subject: [PATCH 057/105] [CP-stable][ Widget Preview ] Pass DTD URI as a constant in a generated file (#179887) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/179139 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples `flutter widget-preview start` creates new cached build artifacts on each run, resulting in increasing disk usage after each run. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) This can result in disk usage slowly creeping up ~50 MiB for each execution of `flutter widget-preview start`. A reboot will currently clear this build artifacts on MacOS and Linux, but not on Windows. ### Workaround: Is there a workaround for this issue? Reboot on MacOS / Linux, clear temporary files manually on Windows. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? 1. Run `flutter widget-preview start --verbose` 2. Find the location of the generated `widget_preview_scaffold` in $TMP 3. Check that there's only a `cache.dill.track.dill` under `build/`. If there's a file of the form `32637b821e3cedec3d78f27cf3f3bc35.cache.dill.track.dill`, this fix wasn't successful. --- .../lib/src/commands/widget_preview.dart | 7 +--- .../preview_code_generator.dart | 29 +++++++++++++++ .../templates/template_manifest.json | 1 + .../lib/src/dtd/dtd_connection_info.dart.tmpl | 5 +++ .../lib/src/dtd/dtd_services.dart.tmpl | 8 ++--- .../preview_code_generator_test.dart | 36 ++++++++++++++++--- .../lib/src/dtd/dtd_connection_info.dart | 5 +++ .../lib/src/dtd/dtd_services.dart | 8 ++--- 8 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl create mode 100644 packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index 8b7aa432109f9..e3d556a931a7b 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -401,6 +401,7 @@ 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 { @@ -463,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(), 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/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 96ee89a1f4b28..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'; /// 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/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 3242940023c19..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 @@ -245,7 +245,12 @@ void main() { 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/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 96ee89a1f4b28..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'; /// 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( From 4c0efac51d9c01e6e4a5de5f7d9fe12dbbc45475 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:10:52 -0800 Subject: [PATCH 058/105] =?UTF-8?q?[CP-stable]Update=20.ci.yaml=20in=20flu?= =?UTF-8?q?tter/flutter=20to=20use=20either=20macOS=2015.5=20or=20macOS=20?= =?UTF-8?q?=E2=80=A6=20(#179799)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? Update .ci.yaml in flutter/flutter to use 15.5 or 15.7.2 *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* Fixes #176930 #176943 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples < Replace with changelog description here > ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) < Replace with impact description here > ### Workaround: Is there a workaround for this issue? < Replace with workaround here > ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? < Replace with validation steps here > --- .ci.yaml | 22 +++++------ engine/src/flutter/.ci.yaml | 8 ++-- .../ci/builders/linux_web_engine_test.json | 2 +- .../src/flutter/ci/builders/local_engine.json | 38 +++++++++---------- .../ci/builders/mac_android_aot_engine.json | 12 +++--- .../flutter/ci/builders/mac_clang_tidy.json | 14 +++---- .../flutter/ci/builders/mac_host_engine.json | 36 +++++++++--------- .../flutter/ci/builders/mac_ios_engine.json | 20 +++++----- engine/src/flutter/ci/builders/mac_unopt.json | 18 ++++----- .../lib/web_ui/dev/generate_builder_json.dart | 2 +- 10 files changed, 86 insertions(+), 86 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 67a42a643d5ec..636cccafb3bd9 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -166,7 +166,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 device_type: none $flutter/osx_sdk : >- { @@ -183,7 +183,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 device_type: none cpu: arm64 $flutter/osx_sdk : >- @@ -203,7 +203,7 @@ platform_properties: ] device_type: none mac_model: "Macmini8,1" - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 tags: > ["devicelab", "hostonly", "mac"] $flutter/osx_sdk : >- @@ -221,7 +221,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -240,7 +240,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -267,7 +267,7 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v3"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-15.1|Mac-15.5|Mac-15.6 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: arm64 device_type: "mokey" @@ -282,7 +282,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.1|Mac-15.5|Mac-15.6 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 device_os: iOS-18 $flutter/osx_sdk : >- { @@ -300,7 +300,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2026"} ] - os: Mac-15.1|Mac-15.5|Mac-15.6 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: x86 device_os: iOS-18 $flutter/osx_sdk : >- @@ -319,7 +319,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "none"} ] - os: Mac-15.1|Mac-15.5|Mac-15.6 + os: Mac-15.1|Mac-15.5|Mac-15.6|Mac-15.7 cpu: arm64 device_os: iOS-18 $flutter/osx_sdk : >- @@ -5562,7 +5562,7 @@ targets: tags: > ["devicelab", "ios", "mac"] task_name: ios_debug_workflow - os: Mac-15.5 + os: Mac-15.5|Mac-15.7 $flutter/osx_sdk : >- { "sdk_version": "17a5295f" @@ -5604,7 +5604,7 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery__transition_perf_e2e_ios drone_dimensions: > - ["device_os=iOS-18","os=Mac-15.1|Mac-15.5|Mac-15.6", "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/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 20bf75063ed6f..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-15.5 + 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-15.5 + - 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-15.5 + - 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-15.5 + - os=Mac-15.5|Mac-15.7 - cpu=x86 - name: Linux windows_android_aot_engine 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 fde9e550d281a..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-15.5", + "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 5ff009df2c515..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-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -70,7 +70,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -103,7 +103,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -136,7 +136,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -170,7 +170,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -206,7 +206,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -370,7 +370,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -403,7 +403,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -436,7 +436,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -520,7 +520,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -604,7 +604,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -636,7 +636,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -669,7 +669,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -702,7 +702,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -841,7 +841,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "device_type=none" ], "gclient_variables": { @@ -925,7 +925,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-15.5", + "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-15.5" + "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-15.5" + "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 ead4cf8b61724..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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -83,7 +83,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -143,7 +143,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -203,7 +203,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -261,7 +261,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=x86" ], "gclient_variables": { @@ -321,7 +321,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "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 cf497d3bc8b01..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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "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-15.5", + "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-15.5", + "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-15.5", + "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-15.5", + "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-15.5", + "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 5ed06bb692e69..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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -84,7 +84,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -140,7 +140,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -205,7 +205,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -256,7 +256,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -307,7 +307,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -370,7 +370,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -424,7 +424,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -477,7 +477,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -543,7 +543,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -600,7 +600,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -656,7 +656,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -722,7 +722,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -777,7 +777,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -832,7 +832,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -899,7 +899,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -957,7 +957,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -1014,7 +1014,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "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 934549e832b59..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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -61,7 +61,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -110,7 +110,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -157,7 +157,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -204,7 +204,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -251,7 +251,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -300,7 +300,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -351,7 +351,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -449,7 +449,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "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 5ee3c8503bc82..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-15.5", + "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-15.5", + "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-15.5", + "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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -216,7 +216,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -275,7 +275,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "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-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -400,7 +400,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { @@ -468,7 +468,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-15.5", + "os=Mac-15.5|Mac-15.7", "cpu=arm64" ], "gclient_variables": { 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 153b4cbbd0fa2..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-15.5', + specificOS: 'Mac-15.5|Mac-15.7', cpu: 'arm64', ), ]; From d7b42531a272651ce6dc7f9e69eeddf7f59d2362 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:23:52 -0800 Subject: [PATCH 059/105] [CP-stable]Ensure that the engine converts std::filesystem::path objects to UTF-8 strings on Windows (#179707) ### Issue Link: https://github.com/flutter/flutter/issues/178896 ### Changelog Description: Fixes an issue that makes Windows apps unable to launch when placed in a path containing non-ASCII characters. ### Impact Description: Apps crash during launch on Windows when run from paths containing non-ASCII characters. ### Workaround: Install the app at a different path. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: Build a Flutter app targeting Windows and move the build output to a directory containing a non-ASCII character. Verify that the app runs when launched from that directory. --- engine/src/flutter/fml/string_conversion.cc | 5 +++++ engine/src/flutter/fml/string_conversion.h | 4 ++++ engine/src/flutter/fml/string_conversion_unittests.cc | 5 +++++ .../shell/platform/windows/flutter_project_bundle.cc | 3 ++- .../shell/platform/windows/flutter_windows_engine.cc | 4 ++-- engine/src/flutter/tools/templater/templater_main.cc | 7 ++++--- 6 files changed, 22 insertions(+), 6 deletions(-) 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/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_windows_engine.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc index d579c818ecfa3..70d7364d56e64 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -274,8 +274,8 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { 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()); if (embedder_api_.RunsAOTCompiledDartCode()) { aot_data_ = project_->LoadAotData(embedder_api_); if (!aot_data_) { 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; From afca4081dd8fd00585583f698a765e4adb440c9a Mon Sep 17 00:00:00 2001 From: jesswrd Date: Thu, 18 Dec 2025 08:10:21 -0800 Subject: [PATCH 060/105] [CP-Stable] Add Flutter Errors for Migrating to AGP 9 (#179765 and #180018) (#180039) This is a manual cherry pick of https://github.com/flutter/flutter/pull/179765 and https://github.com/flutter/flutter/pull/180018 to beta. Combined into one CP PR because the second PR is a fix-forward. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/179914 (beta CP: https://github.com/flutter/flutter/pull/180038) ### Impact Description: Impacted Users (Approximately who will hit this issue, ex. all Flutter devs, Windows developers, all end-customers, apps using X framework feature). Flutter devs who ship to Android and are updating to AGP 9.0.0. ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. Added Flutter Errors to direct users to AGP 9 Migration Flutter docs when upgrading to AGP 9.0.0. ### Workaround: Is there a workaround for this issue? Currently, you can address the errors by looking through the comments at this issue [here](https://github.com/flutter/flutter/issues/175688) or reading Android AGP 9 preview docs [here](https://developer.android.com/build/releases/agp-preview). ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: Create or use an existing Flutter app. Update to AGP 9.0.0. Address the errors as instructed in the Flutter error, then run `flutter run` on the project. --- .../lib/src/android/gradle_errors.dart | 51 ++++++++++++ .../android/gradle_errors_test.dart | 82 +++++++++++++++++++ 2 files changed, 133 insertions(+) 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/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index 31d611f0f920c..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, ]), ); @@ -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) { From 1e3ce74aad2b4cf660433d404dc17225c77b6f26 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Fri, 19 Dec 2025 13:17:05 -0600 Subject: [PATCH 061/105] Partial update for `CHANGELOG` for 3.38.6 release (#180133) Updates `CHANGELOG` with commits I landed this week to be included in the 3.38.6 release due in a few weeks. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78acf13c2568c..17e4ea9b7fef7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,9 +32,16 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.38 Changes +### [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. + ### [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. +- [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) From 0318e792f675ca689172dc32c25c9f69943d576c Mon Sep 17 00:00:00 2001 From: hellohuanlin <41930132+hellohuanlin@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:59:58 -0800 Subject: [PATCH 062/105] [CP][Stable][ios][pv] quick fix to enable and re-enable web view's gesture recognizer (#180522) Stable CP PR: https://github.com/flutter/flutter/pull/180522 Beta CP PR: https://github.com/flutter/flutter/pull/179974 Original PR: https://github.com/flutter/flutter/pull/179908 The "cherry-pick template" linked in https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process/e7b042dd481d4ac66477fb281b6e626e8dba8a4e seems to be broken, so I copied the template from previous CP. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/175099 https://github.com/flutter/flutter/issues/165787 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping of production apps (the app crashes on launch). This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick. WebViews (including ads) on iOS 26 are unclickable after being scrolled or after a Flutter menu is open and then closed. This is a serious regression that impacts revenue. This impacts all Flutter apps running on iOS 26 that use WebViews. ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. < Replace with changelog description here > [flutter/165787, flutter/175099] When WebViews are scrolled on iOS 26, they become unclickable. ### Workaround: Is there a workaround for this issue? None ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Use sample project from https://github.com/flutter/flutter/issues/165787#issuecomment-3429452722. Touch and scroll on an ad, then try to click the ad. The ad will be unclickable. https://github.com/flutter/flutter/issues/175099 https://github.com/flutter/flutter/issues/165787 **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- .../framework/Source/FlutterPlatformViews.mm | 45 +- .../Source/FlutterPlatformViewsTest.mm | 453 ++++++++++++++++++ 2 files changed, 495 insertions(+), 3 deletions(-) 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; From 48cd386c950799a57be6502765cd9d8d503db4c6 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 6 Jan 2026 11:09:06 -0500 Subject: [PATCH 063/105] [CP][stable][web] Fix `resizeToAvoidBottomInset` on Android web (#179581) (#180535) Manual CP of the original PR: https://github.com/flutter/flutter/pull/179581 The "cherry-pick template" linked in https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process/e7b042dd481d4ac66477fb281b6e626e8dba8a4e seems to be broken, so I copied the template from previous CP. ### Issue Link: https://github.com/flutter/flutter/issues/175074 ### Impact Description: All Android users are affected. ### Changelog Description: When the virtual keyboard is closed, the area behind it remains blank and the app only draws in the area that used to be above the keyboard. ### Workaround: None ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? --- .../lib/web_ui/lib/src/engine/window.dart | 54 ++++++++++--- .../lib/web_ui/test/engine/window_test.dart | 80 ++++++++++++------- 2 files changed, 95 insertions(+), 39 deletions(-) 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); + }); + }); } From 67fd08b6062499a15b2788c0e40eef9b0deb647c Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:43:02 -0800 Subject: [PATCH 064/105] [CP-stable]Add a null check for embedded view being added to accessibility tree (#180593) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/180381 https://github.com/flutter/flutter/issues/179922 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping of production apps (the app crashes on launch). This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick. Crash. ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. < Replace with changelog description here > [flutter/180381] Fixes a crash on Android when enabling accessibility, hiding a platform view, and pulling out the top curtain. ### Workaround: Is there a workaround for this issue? No. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run the app from https://github.com/flutter/flutter/issues/179922. --- .../io/flutter/view/AccessibilityBridge.java | 13 +++--- .../flutter/view/AccessibilityBridgeTest.java | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) 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/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); From 78fc3012e45889657f72359b005af7beac47ba3d Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:42:12 -0800 Subject: [PATCH 065/105] Update `engine.version` & `DEPS` for 3.38.6 release (#180605) https://github.com/flutter/flutter/commit/67fd08b6062499a15b2788c0e40eef9b0deb647c was the last cherry-pick to modify the engine. `engine.version` was updated accordingly. `DEPS` updated to use Dart 3.10.7 as per (https://dart.googlesource.com/sdk/+/refs/heads/lkgr-stable) currently and ran `glient sync && tools/dart/create_updated_flutter_deps.py -f /path/to/flutter/DEPS` to ensure no other dependencies needed to be updated. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- DEPS | 2 +- bin/internal/engine.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d0d0743f1efb0..1ab6b2a1ce554 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,7 @@ 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': 'a0daa5004ec02c0638ba6e50791ba9338a87374c', + '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 diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f0eb004794088..9f7ce9c359389 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1527ae0ec577a4ef50e65f6fefcfc1326707d9bf +67fd08b6062499a15b2788c0e40eef9b0deb647c From 360685df28c32de822e7571c7f4a7b007158981b Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:50:01 -0800 Subject: [PATCH 066/105] Update `CHANGELOG` for 3.38.6 release (#180606) Add entries for the newly landed 3.38.6 cherry picks! **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e4ea9b7fef7..55b160b7788d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,9 @@ docs/releases/Hotfix-Documentation-Best-Practices.md - [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) From 8b872868494e429d94fa06dca855c306438b22c0 Mon Sep 17 00:00:00 2001 From: walley892 Date: Thu, 8 Jan 2026 10:49:17 -0800 Subject: [PATCH 067/105] Update engine.version for 3.38.6 release (#180698) Dart version was bumped in https://github.com/flutter/flutter/commit/78fc3012e45889657f72359b005af7beac47ba3d. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9f7ce9c359389..061f1493f9cc0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -67fd08b6062499a15b2788c0e40eef9b0deb647c +78fc3012e45889657f72359b005af7beac47ba3d From e1fce2a6bab312c60c660d2a2553387b73db4826 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 13 Jan 2026 13:16:13 -0500 Subject: [PATCH 068/105] [CP-stable][ Tool ] Fix `flutter run -d all` crash (#180867) ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/179857 ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping of production apps (the app crashes on launch). This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick. `flutter run -d all` causes the tool to crash if multiple devices are available. ### Changelog Description: Explain this cherry pick: * In one line that is accessible to most Flutter developers. * That describes the state prior to the fix. * That includes which platforms are impacted. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples. `flutter run -d all` causes the tool to crash if multiple devices are available. ### Workaround: Is there a workaround for this issue? No. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Run `flutter run -d all` with multiple non-web devices available and verify the application is deployed to all non-web devices. --- packages/flutter_tools/lib/src/run_hot.dart | 53 +++++++++++-------- .../test/general.shard/run_hot_test.dart | 40 ++++++++++++++ 2 files changed, 71 insertions(+), 22 deletions(-) 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/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 { From 3b62efc2a3da49882f43c372e0bc53daef7295a6 Mon Sep 17 00:00:00 2001 From: walley892 Date: Tue, 13 Jan 2026 13:47:42 -0800 Subject: [PATCH 069/105] Update changelog for flutter 3.38.7 stable hotfix (#180931) Updates the changelog to prepare for the 3.38.7 stable hotfix. Includes https://github.com/flutter/flutter/pull/180867 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b160b7788d7..d9a6a608313bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ 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. From 1bec9e55ef560fcb248b2d81059dd52f6d35259d Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 14 Nov 2025 14:22:52 -0800 Subject: [PATCH 070/105] chore: squash all commits on top of 3.35.7 --- .github/workflows/ci.yml | 43 +++ .github/workflows/shorebird_ci.yml | 60 ++++ DEPS | 9 +- engine/src/build/config/compiler/BUILD.gn | 10 +- engine/src/build/toolchain/win/BUILD.gn | 5 +- .../src/build/toolchain/win/tool_wrapper.py | 11 + engine/src/flutter/BUILD.gn | 27 +- engine/src/flutter/build/archives/BUILD.gn | 18 +- .../src/flutter/build/dart/tools/dart_pkg.py | 10 +- engine/src/flutter/common/config.gni | 8 + engine/src/flutter/lib/snapshot/BUILD.gn | 76 +++- engine/src/flutter/runtime/dart_snapshot.cc | 104 ++++-- engine/src/flutter/shell/common/BUILD.gn | 27 ++ engine/src/flutter/shell/common/shell.cc | 10 + .../flutter/shell/common/shorebird/BUILD.gn | 60 ++++ .../shell/common/shorebird/shorebird.cc | 335 ++++++++++++++++++ .../shell/common/shorebird/shorebird.h | 47 +++ .../common/shorebird/shorebird_unittests.cc | 21 ++ .../common/shorebird/snapshots_data_handle.cc | 144 ++++++++ .../common/shorebird/snapshots_data_handle.h | 48 +++ .../snapshots_data_handle_unittests.cc | 177 +++++++++ .../flutter/shell/platform/android/BUILD.gn | 20 +- .../platform/android/android_exports.lst | 12 + .../shell/platform/android/flutter_main.cc | 21 +- .../shell/platform/android/flutter_main.h | 3 + .../flutter/embedding/engine/FlutterJNI.java | 49 ++- .../shell/platform/darwin/ios/BUILD.gn | 10 + .../framework/Source/FlutterDartProject.mm | 33 ++ .../framework/Source/FlutterViewController.mm | 1 + .../shell/platform/darwin/macos/BUILD.gn | 2 + .../macos/framework/Source/FlutterEngine.mm | 58 ++- .../src/flutter/shell/platform/linux/BUILD.gn | 3 + .../flutter/shell/platform/linux/fl_engine.cc | 20 +- .../shell/platform/linux/fl_shorebird.cc | 56 +++ .../shell/platform/linux/fl_shorebird.h | 13 + .../flutter/shell/platform/windows/BUILD.gn | 8 + .../platform/windows/flutter_project_bundle.h | 4 + .../platform/windows/flutter_windows.dll.def | 17 + .../windows/flutter_windows_engine.cc | 150 ++++++++ engine/src/flutter/shell/testing/BUILD.gn | 1 + .../flutter/sky/tools/create_ios_framework.py | 12 +- engine/src/flutter/testing/run_tests.py | 1 + .../flutter_tools/gradle/build.gradle.kts | 1 + .../flutter_tools/lib/src/base/build.dart | 24 +- .../lib/src/build_system/targets/assets.dart | 14 + .../lib/src/build_system/targets/common.dart | 35 ++ .../lib/src/build_system/targets/ios.dart | 6 + .../lib/src/build_system/targets/macos.dart | 6 + packages/flutter_tools/lib/src/cache.dart | 5 + .../lib/src/ios/application_package.dart | 12 + .../lib/src/shorebird/shorebird_yaml.dart | 64 ++++ packages/flutter_tools/lib/src/version.dart | 13 + .../lib/src/windows/build_windows.dart | 1 + .../hermetic/build_macos_test.dart | 41 +++ .../hermetic/build_windows_test.dart | 126 +++++-- .../build_system/targets/macos_test.dart | 182 ++++++++-- .../test/general.shard/cache_test.dart | 197 ++++++---- .../shorebird/shorebird_yaml_test.dart | 101 ++++++ packages/shorebird_tests/.gitignore | 3 + packages/shorebird_tests/README.md | 2 + .../shorebird_tests/analysis_options.yaml | 2 + packages/shorebird_tests/pubspec.yaml | 16 + .../shorebird_tests/test/android_test.dart | 92 +++++ packages/shorebird_tests/test/base_test.dart | 15 + packages/shorebird_tests/test/ios_test.dart | 91 +++++ .../shorebird_tests/test/shorebird_tests.dart | 281 +++++++++++++++ 66 files changed, 2896 insertions(+), 178 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/shorebird_ci.yml create mode 100644 engine/src/flutter/shell/common/shorebird/BUILD.gn create mode 100644 engine/src/flutter/shell/common/shorebird/shorebird.cc create mode 100644 engine/src/flutter/shell/common/shorebird/shorebird.h create mode 100644 engine/src/flutter/shell/common/shorebird/shorebird_unittests.cc create mode 100644 engine/src/flutter/shell/common/shorebird/snapshots_data_handle.cc create mode 100644 engine/src/flutter/shell/common/shorebird/snapshots_data_handle.h create mode 100644 engine/src/flutter/shell/common/shorebird/snapshots_data_handle_unittests.cc create mode 100644 engine/src/flutter/shell/platform/linux/fl_shorebird.cc create mode 100644 engine/src/flutter/shell/platform/linux/fl_shorebird.h create mode 100644 engine/src/flutter/shell/platform/windows/flutter_windows.dll.def create mode 100644 packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart create mode 100644 packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart create mode 100644 packages/shorebird_tests/.gitignore create mode 100644 packages/shorebird_tests/README.md create mode 100644 packages/shorebird_tests/analysis_options.yaml create mode 100644 packages/shorebird_tests/pubspec.yaml create mode 100644 packages/shorebird_tests/test/android_test.dart create mode 100644 packages/shorebird_tests/test/base_test.dart create mode 100644 packages/shorebird_tests/test/ios_test.dart create mode 100644 packages/shorebird_tests/test/shorebird_tests.dart 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/shorebird_ci.yml b/.github/workflows/shorebird_ci.yml new file mode 100644 index 0000000000000..ec147b4489255 --- /dev/null +++ b/.github/workflows/shorebird_ci.yml @@ -0,0 +1,60 @@ +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 + + # TODO(eseidel): This is also set inside shorebird_tests, unclear if + # if it's needed here as well. + 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 + + # 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' }} + # TODO(eseidel): We can't run all flutter_tools tests until we make + # our changes not throw exceptions on missing shorebird.yaml. + # https://github.com/shorebirdtech/shorebird/issues/2392 + run: ../../bin/flutter test test/general.shard/shorebird + 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 diff --git a/DEPS b/DEPS index 1ab6b2a1ce554..fd0f04ed39ccf 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": "b65ce89c8057d6880e00693a7b0ecd7b9e5f61ca", + "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", + "updater_git": "https://github.com/shorebirdtech/updater.git", + "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -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. @@ -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/engine/src/build/config/compiler/BUILD.gn b/engine/src/build/config/compiler/BUILD.gn index 50f1b60eab1a4..54f5ee23ca52b 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/18/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/BUILD.gn b/engine/src/flutter/BUILD.gn index ec7b55d24f152..c8cbc6803dbe9 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" ] } @@ -214,6 +210,7 @@ group("unittests") { "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", "//flutter/shell/geometry:geometry_unittests", + "//flutter/shell/common/shorebird:shorebird_unittests", "//flutter/shell/platform/embedder:embedder_a11y_unittests", "//flutter/shell/platform/embedder:embedder_proctable_unittests", "//flutter/shell/platform/embedder:embedder_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/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/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/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index 198a2e75a7edc..9ab19ef4b7a67 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -56,33 +56,93 @@ static std::shared_ptr SearchMapping( const std::vector& native_library_paths, const char* native_library_symbol_name, bool is_executable) { - // Ask the embedder. There is no fallback as we expect the embedders (via - // their embedding APIs) to just specify the mappings directly. - if (embedder_mapping_callback) { - // Note that mapping will be nullptr if the mapping callback returns an - // invalid mapping. If all the other methods for resolving the data also - // fail, the engine will stop with accompanying error logs. - if (auto mapping = embedder_mapping_callback()) { - return mapping; +#if SHOREBIRD_USE_INTERPRETER + // Detect when we're trying to load a Shorebird patch. + auto patch_path = native_library_path.front(); + bool is_patch = patch_path.find(".vmcode") != std::string::npos; + if (is_patch) { + // We use this terrible hack to load in the patch and then extract the + // symbols from it when the path is not App.framework/App but rather + // foo.vmcode, etc. We read the symbols into static variables, but then I + // believe we need to hold onto the ELF itself, otherwise the symbols + // become invalid. + // "leaked_elf" is meant to indicate that we're not freeing the ELF. + static Dart_LoadedElf* leaked_elf = 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. + const uint8_t* ignored_vm_data = nullptr; + const uint8_t* ignored_vm_instrs = nullptr; + static const uint8_t* isolate_data = nullptr; + static const uint8_t* isolate_instrs = nullptr; + if (leaked_elf == nullptr) { + const char* error = nullptr; + // vmcode files are elf files prefixed with a shorebird linker header. + auto elf_mapping = GetFileMapping(patch_path, false /* executable */); + int elf_file_offset = Shorebird_ReadLinkHeader(elf_mapping->GetMapping(), + elf_mapping->GetSize()); + + leaked_elf = Dart_LoadELF(patch_path.c_str(), elf_file_offset, &error, + &ignored_vm_data, &ignored_vm_instrs, + &isolate_data, &isolate_instrs, + /* load as read-only, not rx */ false); + if (leaked_elf != nullptr) { + FML_LOG(INFO) << "Loaded ELF"; + } else { + FML_LOG(FATAL) << "Failed to load ELF at " << patch_path + << " error: " << error; + abort(); + } } - } - // Attempt to open file at path specified. - if (!file_path.empty()) { - if (auto file_mapping = GetFileMapping(file_path, is_executable)) { - return file_mapping; + FML_LOG(INFO) << "Loading symbol from ELF " << native_library_symbol_name; + + if (native_library_symbol_name == DartSnapshot::kIsolateDataSymbol) { + return std::make_unique(isolate_data, 0, + nullptr, true); + } else if (native_library_symbol_name == + DartSnapshot::kIsolateInstructionsSymbol) { + return std::make_unique(isolate_instrs, 0, + nullptr, true); + } + // Fall through to normal lookups for VM data and instructions. + // This fallthrough depends on the fact that NativeLibrary below can't + // read the ELF out of our .vmcode files. + } else { + // Only try to open the file if we're not loading a patch. +#endif + + // Ask the embedder. There is no fallback as we expect the embedders (via + // their embedding APIs) to just specify the mappings directly. + if (embedder_mapping_callback) { + // Note that mapping will be nullptr if the mapping callback returns an + // invalid mapping. If all the other methods for resolving the data also + // fail, the engine will stop with accompanying error logs. + if (auto mapping = embedder_mapping_callback()) { + return mapping; + } } - } - // Look in application specified native library if specified. - for (const std::string& path : native_library_paths) { - auto native_library = fml::NativeLibrary::Create(path.c_str()); - auto symbol_mapping = std::make_unique( - native_library, native_library_symbol_name); - if (symbol_mapping->GetMapping() != nullptr) { - return symbol_mapping; + // Attempt to open file at path specified. + if (!file_path.empty()) { + if (auto file_mapping = GetFileMapping(file_path, is_executable)) { + return file_mapping; + } } - } + + // Look in application specified native library if specified. + for (const std::string& path : native_library_paths) { + auto native_library = fml::NativeLibrary::Create(path.c_str()); + auto symbol_mapping = std::make_unique( + native_library, native_library_symbol_name); + if (symbol_mapping->GetMapping() != nullptr) { + return symbol_mapping; + } + } + +#if SHOREBIRD_USE_INTERPRETER + } // !is_patch +#endif // Look inside the currently loaded process. { diff --git a/engine/src/flutter/shell/common/BUILD.gn b/engine/src/flutter/shell/common/BUILD.gn index 78f52396582f6..45d48d8ac8873 100644 --- a/engine/src/flutter/shell/common/BUILD.gn +++ b/engine/src/flutter/shell/common/BUILD.gn @@ -153,6 +153,8 @@ source_set("common") { "//flutter/skia", ] + include_dirs = [ "//flutter/updater" ] + if (impeller_supports_rendering) { sources += [ "snapshot_controller_impeller.cc", @@ -161,6 +163,31 @@ source_set("common") { deps += [ "//flutter/impeller" ] } + + # Needed to compile flutter_tester for macOS. + if (host_os == "mac" && target_os == "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" ] + } + } + + # Needed to compile flutter_tester for Windows. + if (host_os == "win" && target_os == "win") { + if (target_cpu == "x64") { + libs = [ + "userenv.lib", + "//flutter/third_party/updater/target/x86_64-pc-windows-msvc/release/updater.lib", + ] + } + } + + if (host_os == "linux" && target_os == "linux") { + if (target_cpu == "x64") { + libs = [ "//flutter/third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a" ] + } + } } # These are in their own source_set to avoid a dependency cycle with //common/graphics diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 73d05330599da..662a0f8393491 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 "third_party/updater/library/include/updater.h" + namespace flutter { constexpr char kSkiaChannel[] = "flutter/skia"; @@ -521,6 +523,14 @@ Shell::Shell(DartVMRef vm, is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)), weak_factory_gpu_(nullptr), weak_factory_(this) { + // FIXME: This is probably the wrong place to hook into. +#if SHOREBIRD_PLATFORM_SUPPORTED + if (!vm_) { + shorebird_report_launch_failure(); + } else { + shorebird_report_launch_success(); + } +#endif 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/shorebird/BUILD.gn b/engine/src/flutter/shell/common/shorebird/BUILD.gn new file mode 100644 index 0000000000000..2c7def6991542 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/BUILD.gn @@ -0,0 +1,60 @@ +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", + ] +} + +source_set("shorebird") { + sources = [ + "shorebird.cc", + "shorebird.h", + ] + + deps = [ + ":snapshots_data_handle", + "//flutter/fml", + "//flutter/runtime", + "//flutter/runtime:libdart", + "//flutter/shell/common", + "//flutter/shell/platform/embedder:embedder_headers", + ] + + include_dirs = [ "//flutter/updater" ] +} + +if (enable_unittests) { + test_fixtures("shorebird_fixtures") { + fixtures = [] + } + + executable("shorebird_unittests") { + testonly = true + + sources = [ + "shorebird_unittests.cc", + "snapshots_data_handle_unittests.cc", + ] + + # This only includes snapshots_data_handle and not shorebird because + # shorebird fails to link due to a missing updater lib. + deps = [ + ":shorebird", + ":shorebird_fixtures", + ":snapshots_data_handle", + "//flutter/runtime", + "//flutter/testing", + "//flutter/testing:fixture_test", + ] + } +} 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..a2b2f382820a1 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -0,0 +1,335 @@ + +#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/switches.h" +#include "fml/logging.h" +#include "shell/platform/embedder/embedder.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +#include "third_party/updater/library/include/updater.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 + +// TODO(eseidel): I believe we need to leak these or we'll sometimes crash +// when using the base snapshot in mixed mode. This likely will not play +// nicely with multi-engine support and will need to be refactored. +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()); +} + +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); +}; + +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 ""; +} + +// FIXME: consolidate this with the other ConfigureShorebird +bool ConfigureShorebird(const ShorebirdConfigArgs& args, + std::string& patch_path) { + patch_path = fml::PathToUtf8(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); + + bool init_result; + // Using a block to make AppParameters lifetime explicit. + { + AppParameters app_parameters; + // 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; + } + + app_parameters.release_version = release_version.c_str(); + app_parameters.code_cache_dir = code_cache_dir.c_str(); + app_parameters.app_storage_dir = app_storage_dir.c_str(); + + // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c + std::vector c_paths{}; + c_paths.push_back(args.release_app_library_path.c_str()); + // Do not modify application_library_path or c_strings will invalidate. + + app_parameters.original_libapp_paths = c_paths.data(); + app_parameters.original_libapp_paths_size = c_paths.size(); + + // shorebird_init copies from app_parameters and shorebirdYaml. + init_result = shorebird_init(&app_parameters, ShorebirdFileCallbacks(), + args.shorebird_yaml.c_str()); + } + + // We've decided not to support synchronous updates on launch for now. + // It's a terrible user experience (having the app hang on launch) and + // instead we will provide examples of how to build a custom update UI + // within Dart, including updating as part of login, etc. + // https://github.com/shorebirdtech/shorebird/issues/950 + + FML_LOG(INFO) << "Checking for active patch"; + shorebird_validate_next_boot_patch(); + char* c_active_path = shorebird_next_boot_patch_path(); + if (c_active_path != NULL) { + patch_path = c_active_path; + shorebird_free_string(c_active_path); + FML_LOG(INFO) << "Shorebird updater: patch path: " << patch_path; + } else { + FML_LOG(INFO) << "Shorebird updater: no active patch."; + } + + // We are careful only to report a launch start in the case where it's the + // first time we've configured shorebird this process. Otherwise we could end + // up in a case where we report a launch start, but never a completion (e.g. + // from package:flutter_work_manager which sometimes creates a FlutterEngine + // (and thus configures shorebird) but never runs it. The proper fix for this + // is probably to move the launch_start() call to be later in the lifecycle + // (when the snapshot is loaded and run, rather than when FlutterEngine is + // initialized). This "hack" will still have a problem where FlutterEngine is + // initialized but never run before the app is quit, could still cause us to + // suddenly mark-bad a patch that was never actually attempted to launch. + if (!init_result) { + return false; + } + + // Once start_update_thread is called, the next_boot_patch* functions may + // change their return values if the shorebird_report_launch_failed + // function is called. + shorebird_report_launch_start(); + + if (shorebird_should_auto_update()) { + FML_LOG(INFO) << "Starting Shorebird update"; + shorebird_start_update_thread(); + } else { + FML_LOG(INFO) + << "Shorebird auto_update disabled, not checking for updates."; + } + + return true; +} + +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); + + bool init_result; + // Using a block to make AppParameters lifetime explicit. + { + AppParameters app_parameters; + // Combine version and version_code into a single string. + // We could also pass these separately through to the updater if needed. + auto release_version = version + "+" + version_code; + app_parameters.release_version = release_version.c_str(); + app_parameters.code_cache_dir = code_cache_dir.c_str(); + app_parameters.app_storage_dir = app_storage_dir.c_str(); + + // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c + std::vector c_paths{}; + for (const auto& string : settings.application_library_path) { + c_paths.push_back(string.c_str()); + } + // Do not modify application_library_path or c_strings will invalidate. + + app_parameters.original_libapp_paths = c_paths.data(); + app_parameters.original_libapp_paths_size = c_paths.size(); + + // shorebird_init copies from app_parameters and shorebirdYaml. + init_result = shorebird_init(&app_parameters, ShorebirdFileCallbacks(), + shorebird_yaml.c_str()); + } + + // We've decided not to support synchronous updates on launch for now. + // It's a terrible user experience (having the app hang on launch) and + // instead we will provide examples of how to build a custom update UI + // within Dart, including updating as part of login, etc. + // 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_validate_next_boot_patch(); + char* c_active_path = shorebird_next_boot_patch_path(); + if (c_active_path != NULL) { + std::string active_path = c_active_path; + shorebird_free_string(c_active_path); + 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_path.insert( + settings.application_library_path.begin(), active_path); +#else + settings.application_library_path.clear(); + settings.application_library_path.emplace_back(active_path); +#endif + } else { + FML_LOG(INFO) << "Shorebird updater: no active patch."; + } + + // We are careful only to report a launch start in the case where it's the + // first time we've configured shorebird this process. Otherwise we could end + // up in a case where we report a launch start, but never a completion (e.g. + // from package:flutter_work_manager which sometimes creates a FlutterEngine + // (and thus configures shorebird) but never runs it. The proper fix for this + // is probably to move the launch_start() call to be later in the lifecycle + // (when the snapshot is loaded and run, rather than when FlutterEngine is + // initialized). This "hack" will still have a problem where FlutterEngine is + // initialized but never run before the app is quit, could still cause us to + // suddenly mark-bad a patch that was never actually attempted to launch. + if (!init_result) { + return; + } + + // Once start_update_thread is called, the next_boot_patch* functions may + // change their return values if the shorebird_report_launch_failed + // function is called. + shorebird_report_launch_start(); + + if (shorebird_should_auto_update()) { + FML_LOG(INFO) << "Starting Shorebird update"; + shorebird_start_update_thread(); + } else { + FML_LOG(INFO) + << "Shorebird auto_update disabled, not checking for updates."; + } +} + +void* FileCallbacksImpl::Open() { + return SnapshotsDataHandle::createForSnapshots(*vm_snapshot, + *isolate_snapshot) + .release(); +} + +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..c6873c5014a00 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/shorebird.h @@ -0,0 +1,47 @@ +#ifndef FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ +#define FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ + +#include "flutter/common/settings.h" +#include "shell/platform/embedder/embedder.h" + +namespace flutter { + +struct ReleaseVersion { + std::string version; + std::string build_number; +}; + +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) {} +}; + +bool ConfigureShorebird(const ShorebirdConfigArgs& args, + std::string& patch_path); + +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); + +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/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index 3d92422cccb3f..7beb4ee4d8fb6 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", @@ -184,6 +185,8 @@ source_set("flutter_shell_native_src") { public_configs = [ "//flutter:config" ] + include_dirs = [ "//flutter/updater" ] + defines = [] libs = [ @@ -191,6 +194,17 @@ source_set("flutter_shell_native_src") { "EGL", "GLESv2", ] + 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 { + assert(false, "Unsupported target_cpu") + } } action("gen_android_build_config_java") { @@ -797,8 +811,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..d881ca39efd3f 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" @@ -29,6 +30,8 @@ #include "impeller/toolkit/android/proc_table.h" #include "txt/platform.h" +#include "third_party/updater/library/include/updater.h" + namespace flutter { constexpr int kMinimumAndroidApiLevelForImpeller = 29; @@ -93,6 +96,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 +157,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 +261,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/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/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index 911ee431e2516..fd167854107b1 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -75,6 +75,14 @@ source_set("flutter_framework_source") { "//build/config/ios:ios_application_extension", ] + 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 { + assert(false, "Unsupported target_cpu") + } + sources = [ "framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterAppDelegate_Internal.h", @@ -194,12 +202,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/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/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_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/windows/BUILD.gn b/engine/src/flutter/shell/platform/windows/BUILD.gn index 62730cc2f85df..550a4b7dc124b 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: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.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 70d7364d56e64..32a6a675e1cf2 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,148 @@ 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) { + std::string assets_path_string = project_->assets_path().u8string(); + std::string icu_path_string = project_->icu_path().u8string(); + if (!project_->HasValidPaths()) { FML_LOG(ERROR) << "Missing or unresolvable paths to assets."; return false; } 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 +547,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/packages/flutter_tools/gradle/build.gradle.kts b/packages/flutter_tools/gradle/build.gradle.kts index 31fc5cbaedc50..84a0f8a6e2ca8 100644 --- a/packages/flutter_tools/gradle/build.gradle.kts +++ b/packages/flutter_tools/gradle/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { // * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt 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.11.1") testImplementation("org.mockito:mockito-core:5.8.0") 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/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart index be7cef8103597..1aa6516ea01a3 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,19 @@ 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: globals.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/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..aea07db785087 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 = @@ -532,6 +533,10 @@ class Cache { ? 'https://storage.googleapis.com' : '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/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/shorebird/shorebird_yaml.dart b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart new file mode 100644 index 0000000000000..9e40f392b7eb8 --- /dev/null +++ b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart @@ -0,0 +1,64 @@ +// 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'); + 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/version.dart b/packages/flutter_tools/lib/src/version.dart index ae26f300a5548..ca0493a163f87 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -1049,6 +1049,19 @@ class GitTagVersion { } } + // Check if running on a Shorebird release branch. + final String shorebirdFlutterReleases = _runGit( + 'git for-each-ref --contains $gitRef --format %(refname:short) refs/remotes/origin/flutter_release/*', + processUtils, + workingDirectory, + ).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/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/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/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index aa31e06bfcddd..4ada1d72a0f8e 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 @@ -142,7 +142,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 +236,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 +257,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 +299,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 +328,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 +351,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 +389,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 +411,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 +436,8 @@ void main() { () async { fileSystem .directory( - artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: BuildMode.debug), + artifacts.getArtifactPath(Artifact.flutterMacOSFramework, + mode: BuildMode.debug), ) .createSync(); fileSystem @@ -447,20 +470,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 +591,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 +633,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}/App.framework.dSYM/Contents/Resources/DWARF/App') .createSync(recursive: true); - fileSystem.file('${environment.buildDir.path}/native_assets.json').createSync(); + 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 +666,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 +710,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 +749,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 +787,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 +804,54 @@ void main() { }, ); + testUsingContext( + 'ReleaseMacOSBundleFlutterAssets updates shorebird.yaml if present', + () async { + environment.defines[kBuildMode] = 'release'; + environment.defines[kXcodeAction] = 'install'; + environment.defines[kFlavor] = 'internal'; + + 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); + fileSystem + .file(fileSystem.path + .join(environment.buildDir.path, 'App.framework', 'App')) + .createSync(recursive: true); + final String shorebirdYamlPath = fileSystem.path.join( + environment.buildDir.path, + 'App.framework', + 'Versions', + 'A', + 'Resources', + 'flutter_assets', + 'shorebird.yaml', + ); + fileSystem.file(fileSystem.path + .join(environment.buildDir.path, 'App.framework', 'App')) + ..createSync(recursive: true) + ..writeAsStringSync(''' +# Some other text that should be removed +app_id: base-app-id +flavors: + internal: internal-app-id + stable: stable-app-id +'''); + + await const ReleaseMacOSBundleFlutterAssets().build(environment); + + expect(fileSystem.file(shorebirdYamlPath).readAsStringSync(), + 'app_id: internal-app-id'); + }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }, + ); + testUsingContext( 'DebugMacOSFramework creates universal binary', () async { @@ -782,7 +881,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, ], ), ); @@ -951,14 +1053,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..d078b7fedd4fe 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,7 +936,8 @@ 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...']); @@ -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"'), ), ); }); @@ -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/shorebird/shorebird_yaml_test.dart b/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart new file mode 100644 index 0000000000000..602de37681555 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart @@ -0,0 +1,101 @@ +// 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 +'''; + 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', + }); + 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_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/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..4bead2de4503e --- /dev/null +++ b/packages/shorebird_tests/test/shorebird_tests.dart @@ -0,0 +1,281 @@ +import 'dart:async'; +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' : ''}', + ), + ); + +/// Runs a flutter command using the correct binary ([_flutterBinaryFile]) with the given arguments. +Future _runFlutterCommand( + List arguments, { + required Directory workingDirectory, + Map? environment, +}) { + return Process.run( + _flutterBinaryFile.absolute.path, + arguments, + workingDirectory: workingDirectory.path, + environment: { + 'FLUTTER_STORAGE_BASE_URL': 'https://download.shorebird.dev', + if (environment != null) ...environment, + }, + ); +} + +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; + } +} From a9c7ed5ddd7a60ac926002b73678a8e93c6a4d17 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 14 Nov 2025 14:45:37 -0800 Subject: [PATCH 071/105] chore: roll Dart to 7c3906e78c874dd834d1a135a3e11bc329b76aef --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index fd0f04ed39ccf..a4c2b90b3acc6 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "b65ce89c8057d6880e00693a7b0ecd7b9e5f61ca", + "dart_sdk_revision": "7c3906e78c874dd834d1a135a3e11bc329b76aef", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", From 52ead0248116066628b9ee0ab22d9da496474d26 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 14 Nov 2025 15:04:34 -0800 Subject: [PATCH 072/105] chore: run et format --- engine/src/flutter/BUILD.gn | 2 +- engine/src/flutter/shell/platform/windows/BUILD.gn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index c8cbc6803dbe9..348f732c329ed 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -209,8 +209,8 @@ group("unittests") { "//flutter/runtime:no_dart_plugin_registrant_unittests", "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", - "//flutter/shell/geometry:geometry_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", "//flutter/shell/platform/embedder:embedder_unittests", diff --git a/engine/src/flutter/shell/platform/windows/BUILD.gn b/engine/src/flutter/shell/platform/windows/BUILD.gn index 550a4b7dc124b..993c4860a5f01 100644 --- a/engine/src/flutter/shell/platform/windows/BUILD.gn +++ b/engine/src/flutter/shell/platform/windows/BUILD.gn @@ -165,7 +165,7 @@ source_set("flutter_windows_source") { ":flutter_windows_headers", "//flutter/fml", "//flutter/impeller/renderer/backend/gles", - "//flutter/shell/common/shorebird:shorebird", + "//flutter/shell/common/shorebird", "//flutter/shell/geometry", "//flutter/shell/platform/common:common_cpp", "//flutter/shell/platform/common:common_cpp_input", From 4b86a85cc8aa35695e7f119ef93fe6c737410888 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 14 Nov 2025 16:06:55 -0800 Subject: [PATCH 073/105] fix: update name to application_library_paths --- .../flutter/shell/common/shorebird/shorebird.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index a2b2f382820a1..ec2bc6bf3c9cd 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -144,7 +144,7 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c std::vector c_paths{}; c_paths.push_back(args.release_app_library_path.c_str()); - // Do not modify application_library_path or c_strings will invalidate. + // Do not modify application_library_paths or c_strings will invalidate. app_parameters.original_libapp_paths = c_paths.data(); app_parameters.original_libapp_paths_size = c_paths.size(); @@ -238,10 +238,10 @@ void ConfigureShorebird(std::string code_cache_path, // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c std::vector c_paths{}; - for (const auto& string : settings.application_library_path) { + for (const auto& string : settings.application_library_paths) { c_paths.push_back(string.c_str()); } - // Do not modify application_library_path or c_strings will invalidate. + // Do not modify application_library_paths or c_strings will invalidate. app_parameters.original_libapp_paths = c_paths.data(); app_parameters.original_libapp_paths_size = c_paths.size(); @@ -273,11 +273,11 @@ void ConfigureShorebird(std::string code_cache_path, // 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_path.insert( - settings.application_library_path.begin(), active_path); + settings.application_library_paths.insert( + settings.application_library_paths.begin(), active_path); #else - settings.application_library_path.clear(); - settings.application_library_path.emplace_back(active_path); + settings.application_library_paths.clear(); + settings.application_library_paths.emplace_back(active_path); #endif } else { FML_LOG(INFO) << "Shorebird updater: no active patch."; From 4b1103b09f308e191a6f942e875f094a78a454c7 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 14 Nov 2025 17:18:37 -0800 Subject: [PATCH 074/105] fix: attempt to fix builds --- engine/src/flutter/runtime/dart_snapshot.cc | 2 +- .../flutter/shell/platform/windows/flutter_windows_engine.cc | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/engine/src/flutter/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index 9ab19ef4b7a67..d36e0730eb8c0 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -58,7 +58,7 @@ static std::shared_ptr SearchMapping( bool is_executable) { #if SHOREBIRD_USE_INTERPRETER // Detect when we're trying to load a Shorebird patch. - auto patch_path = native_library_path.front(); + auto patch_path = native_library_paths.front(); bool is_patch = patch_path.find(".vmcode") != std::string::npos; if (is_patch) { // We use this terrible hack to load in the patch and then extract the 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 32a6a675e1cf2..22b028beb03f4 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -395,9 +395,6 @@ bool SetUpShorebird(std::string assets_path_string, std::string& patch_path) { } bool FlutterWindowsEngine::Run(std::string_view entrypoint) { - std::string assets_path_string = project_->assets_path().u8string(); - std::string icu_path_string = project_->icu_path().u8string(); - if (!project_->HasValidPaths()) { FML_LOG(ERROR) << "Missing or unresolvable paths to assets."; return false; From fe4cc75c3870a0663375bf71613667b96f63aee6 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 17 Nov 2025 08:26:44 -0800 Subject: [PATCH 075/105] chore: add missing header for ios --- engine/src/flutter/runtime/dart_snapshot.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/flutter/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index d36e0730eb8c0..28ccb1cc46141 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" From 146de09e0e64ac0be15d32d7e1970a2349fab01c Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 17 Nov 2025 10:45:57 -0800 Subject: [PATCH 076/105] fix: linux android build --- engine/src/build/config/compiler/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/build/config/compiler/BUILD.gn b/engine/src/build/config/compiler/BUILD.gn index 54f5ee23ca52b..87b571ff75e00 100644 --- a/engine/src/build/config/compiler/BUILD.gn +++ b/engine/src/build/config/compiler/BUILD.gn @@ -667,7 +667,7 @@ config("runtime_library") { } # 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/18/lib/linux/${current_android_cpu}/" ] + lib_dirs += [ "${android_toolchain_root}/lib/clang/19/lib/linux/${current_android_cpu}/" ] libs += [ "clang_rt.builtins-${current_android_cpu}-android" ] } From 306466e2b65a6c724d949280da36cd8f17580263 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 17 Nov 2025 14:35:11 -0800 Subject: [PATCH 077/105] chore: roll dart to 85ccbcf7c729f493acba96b392d9acab4b998565 to fix async crash --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index a4c2b90b3acc6..fcd976f790d68 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "7c3906e78c874dd834d1a135a3e11bc329b76aef", + "dart_sdk_revision": "85ccbcf7c729f493acba96b392d9acab4b998565", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", From 60f5ea46217488de2f7a62ae8d7a4341be44dd09 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 17 Nov 2025 15:23:56 -0800 Subject: [PATCH 078/105] fix: attempt to fix shorebird flutter_tools changes --- .../lib/src/build_system/targets/assets.dart | 6 ++---- packages/flutter_tools/lib/src/version.dart | 16 +++++++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) 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 1aa6516ea01a3..d5256761bd69f 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart @@ -168,12 +168,10 @@ Future copyAssets( updateShorebirdYaml( environment.defines[kFlavor], file.path, - environment: globals.platform.environment, + environment: environment.platform.environment, ); } on Exception catch (error) { - throw Exception( - 'Failed to generate shorebird configuration. Error: $error', - ); + throw Exception('Failed to generate shorebird configuration. Error: $error'); } } } diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index ca0493a163f87..5dcd14400b673 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -1050,11 +1050,17 @@ class GitTagVersion { } // Check if running on a Shorebird release branch. - final String shorebirdFlutterReleases = _runGit( - 'git for-each-ref --contains $gitRef --format %(refname:short) refs/remotes/origin/flutter_release/*', - processUtils, - workingDirectory, - ).trim(); + 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; From b4d145e8f591ad659d934ddf476e934556c3fb05 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 24 Nov 2025 14:57:57 -0800 Subject: [PATCH 079/105] chore: roll Dart to 761141da83b656cfe9d85c734e61cdbaea095d69 --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index fcd976f790d68..da60dd2df0d02 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "85ccbcf7c729f493acba96b392d9acab4b998565", + "dart_sdk_revision": "761141da83b656cfe9d85c734e61cdbaea095d69", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", From fd3c929bc7677c721ad588366bc472ca52756362 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 4 Dec 2025 16:28:18 -0800 Subject: [PATCH 080/105] chore: roll dart to 790993a4fb8ecf784de4e29532d75b027658f27e --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index da60dd2df0d02..e6f31dc15b8a5 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "761141da83b656cfe9d85c734e61cdbaea095d69", + "dart_sdk_revision": "790993a4fb8ecf784de4e29532d75b027658f27e", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", From 7b278fefb943a664b8694e353eb2b80c1c08c3f7 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 12 Dec 2025 09:04:44 -0800 Subject: [PATCH 081/105] feat: make it possible to load two patches into the runtime at once (#96) * fix: stop using globals for patch data * chore: run et format * chore: add missing files * test: add unittest * chore: run et format * chore: move elf_cache down into runtime * chore: rename elf* to patch* * chore: clean up logs * chore: clean up comments * chore: use Shorebird dart * chore: small cleanup --- bin/internal/update_dart_sdk.sh | 2 +- engine/src/flutter/runtime/BUILD.gn | 4 + engine/src/flutter/runtime/dart_snapshot.cc | 127 +++++--------- engine/src/flutter/runtime/shorebird/BUILD.gn | 15 ++ .../flutter/runtime/shorebird/patch_cache.cc | 160 ++++++++++++++++++ .../flutter/runtime/shorebird/patch_cache.h | 104 ++++++++++++ .../runtime/shorebird/patch_mapping.cc | 51 ++++++ .../flutter/runtime/shorebird/patch_mapping.h | 55 ++++++ .../flutter/shell/common/shorebird/BUILD.gn | 2 + .../common/shorebird/patch_cache_unittests.cc | 70 ++++++++ 10 files changed, 505 insertions(+), 85 deletions(-) create mode 100644 engine/src/flutter/runtime/shorebird/BUILD.gn create mode 100644 engine/src/flutter/runtime/shorebird/patch_cache.cc create mode 100644 engine/src/flutter/runtime/shorebird/patch_cache.h create mode 100644 engine/src/flutter/runtime/shorebird/patch_mapping.cc create mode 100644 engine/src/flutter/runtime/shorebird/patch_mapping.h create mode 100644 engine/src/flutter/shell/common/shorebird/patch_cache_unittests.cc 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/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_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index 28ccb1cc46141..b822d98604712 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -14,6 +14,10 @@ #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 + namespace flutter { const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData"; @@ -57,93 +61,33 @@ static std::shared_ptr SearchMapping( const std::vector& native_library_paths, const char* native_library_symbol_name, bool is_executable) { -#if SHOREBIRD_USE_INTERPRETER - // Detect when we're trying to load a Shorebird patch. - auto patch_path = native_library_paths.front(); - bool is_patch = patch_path.find(".vmcode") != std::string::npos; - if (is_patch) { - // We use this terrible hack to load in the patch and then extract the - // symbols from it when the path is not App.framework/App but rather - // foo.vmcode, etc. We read the symbols into static variables, but then I - // believe we need to hold onto the ELF itself, otherwise the symbols - // become invalid. - // "leaked_elf" is meant to indicate that we're not freeing the ELF. - static Dart_LoadedElf* leaked_elf = 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. - const uint8_t* ignored_vm_data = nullptr; - const uint8_t* ignored_vm_instrs = nullptr; - static const uint8_t* isolate_data = nullptr; - static const uint8_t* isolate_instrs = nullptr; - if (leaked_elf == nullptr) { - const char* error = nullptr; - // vmcode files are elf files prefixed with a shorebird linker header. - auto elf_mapping = GetFileMapping(patch_path, false /* executable */); - int elf_file_offset = Shorebird_ReadLinkHeader(elf_mapping->GetMapping(), - elf_mapping->GetSize()); - - leaked_elf = Dart_LoadELF(patch_path.c_str(), elf_file_offset, &error, - &ignored_vm_data, &ignored_vm_instrs, - &isolate_data, &isolate_instrs, - /* load as read-only, not rx */ false); - if (leaked_elf != nullptr) { - FML_LOG(INFO) << "Loaded ELF"; - } else { - FML_LOG(FATAL) << "Failed to load ELF at " << patch_path - << " error: " << error; - abort(); - } - } - - FML_LOG(INFO) << "Loading symbol from ELF " << native_library_symbol_name; - - if (native_library_symbol_name == DartSnapshot::kIsolateDataSymbol) { - return std::make_unique(isolate_data, 0, - nullptr, true); - } else if (native_library_symbol_name == - DartSnapshot::kIsolateInstructionsSymbol) { - return std::make_unique(isolate_instrs, 0, - nullptr, true); - } - // Fall through to normal lookups for VM data and instructions. - // This fallthrough depends on the fact that NativeLibrary below can't - // read the ELF out of our .vmcode files. - } else { - // Only try to open the file if we're not loading a patch. -#endif - - // Ask the embedder. There is no fallback as we expect the embedders (via - // their embedding APIs) to just specify the mappings directly. - if (embedder_mapping_callback) { - // Note that mapping will be nullptr if the mapping callback returns an - // invalid mapping. If all the other methods for resolving the data also - // fail, the engine will stop with accompanying error logs. - if (auto mapping = embedder_mapping_callback()) { - return mapping; - } + // Ask the embedder. There is no fallback as we expect the embedders (via + // their embedding APIs) to just specify the mappings directly. + if (embedder_mapping_callback) { + // Note that mapping will be nullptr if the mapping callback returns an + // invalid mapping. If all the other methods for resolving the data also + // fail, the engine will stop with accompanying error logs. + if (auto mapping = embedder_mapping_callback()) { + return mapping; } + } - // Attempt to open file at path specified. - if (!file_path.empty()) { - if (auto file_mapping = GetFileMapping(file_path, is_executable)) { - return file_mapping; - } + // Attempt to open file at path specified. + if (!file_path.empty()) { + if (auto file_mapping = GetFileMapping(file_path, is_executable)) { + return file_mapping; } + } - // Look in application specified native library if specified. - for (const std::string& path : native_library_paths) { - auto native_library = fml::NativeLibrary::Create(path.c_str()); - auto symbol_mapping = std::make_unique( - native_library, native_library_symbol_name); - if (symbol_mapping->GetMapping() != nullptr) { - return symbol_mapping; - } + // Look in application specified native library if specified. + for (const std::string& path : native_library_paths) { + auto native_library = fml::NativeLibrary::Create(path.c_str()); + auto symbol_mapping = std::make_unique( + native_library, native_library_symbol_name); + if (symbol_mapping->GetMapping() != nullptr) { + return symbol_mapping; } - -#if SHOREBIRD_USE_INTERPRETER - } // !is_patch -#endif + } // Look inside the currently loaded process. { @@ -206,7 +150,14 @@ static std::shared_ptr ResolveIsolateData( 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::kIsolateDataSymbol)) { + return mapping; + } +#endif // SHOREBIRD_USE_INTERPRETER return SearchMapping( settings.isolate_snapshot_data, // embedder_mapping_callback settings.isolate_snapshot_data_path, // file_path @@ -226,7 +177,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..facee07ba5cd1 --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/BUILD.gn @@ -0,0 +1,15 @@ +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", + ] +} 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..30c99aea3a011 --- /dev/null +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -0,0 +1,160 @@ +// 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 "flutter/fml/logging.h" +#include "flutter/fml/mapping.h" +#include "flutter/runtime/shorebird/patch_mapping.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, + /* load as read-only, not rx */ false); + + 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; + + 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/shorebird/BUILD.gn b/engine/src/flutter/shell/common/shorebird/BUILD.gn index 2c7def6991542..dc2fc5515bd7c 100644 --- a/engine/src/flutter/shell/common/shorebird/BUILD.gn +++ b/engine/src/flutter/shell/common/shorebird/BUILD.gn @@ -42,6 +42,7 @@ if (enable_unittests) { testonly = true sources = [ + "patch_cache_unittests.cc", "shorebird_unittests.cc", "snapshots_data_handle_unittests.cc", ] @@ -53,6 +54,7 @@ if (enable_unittests) { ":shorebird_fixtures", ":snapshots_data_handle", "//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 From 3e28fa12865294f3346e4e13f6229d5b8d790b62 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 12 Dec 2025 14:36:18 -0800 Subject: [PATCH 082/105] feat: shorebird flutter should work without setting FLUTTER_STORAGE_BASE_URL (#97) * fix: make dart/flutter work without FLUTTER_STORAGE_BASE_URL * feat: shorebird flutter should work without setting FLUTTER_STORAGE_BASE_URL * fix: flutter_tools test fixes * fix: enable running flutter_tools tests * chore: remove unnecessary workflow --- .github/workflows/files-changed.yml | 41 ------------- .github/workflows/shorebird_ci.yml | 5 +- bin/internal/update_dart_sdk.ps1 | 2 +- dev/bots/post_process_docs.dart | 2 +- dev/bots/unpublish_package.dart | 2 +- .../settings.gradle | 2 +- .../settings.gradle.kts | 2 +- dev/tools/create_api_docs.dart | 2 +- engine/src/flutter/build/zip_bundle.gni | 2 +- .../impeller/toolkit/interop/README.md | 2 +- .../web_ui/dev/steps/copy_artifacts_step.dart | 2 +- .../gradle/aar_init_script.gradle | 2 +- .../src/main/kotlin/FlutterPluginConstants.kt | 2 +- packages/flutter_tools/lib/src/cache.dart | 4 +- .../lib/src/http_host_validator.dart | 2 +- .../test/general.shard/base/build_test.dart | 14 +++++ .../build_system/targets/common_test.dart | 12 ++++ .../build_system/targets/macos_test.dart | 59 +++++++++++++++---- .../test/general.shard/cache_test.dart | 4 +- .../test/general.shard/version_test.dart | 14 +++++ 20 files changed, 104 insertions(+), 73 deletions(-) delete mode 100644 .github/workflows/files-changed.yml 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 index ec147b4489255..7b712b1583b87 100644 --- a/.github/workflows/shorebird_ci.yml +++ b/.github/workflows/shorebird_ci.yml @@ -46,10 +46,7 @@ jobs: - 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' }} - # TODO(eseidel): We can't run all flutter_tools tests until we make - # our changes not throw exceptions on missing shorebird.yaml. - # https://github.com/shorebirdtech/shorebird/issues/2392 - run: ../../bin/flutter test test/general.shard/shorebird + run: ../../bin/flutter test test/general.shard working-directory: packages/flutter_tools - name: 🐦 Run Shorebird Tests 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/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/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/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/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/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/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/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/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/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index aea07db785087..2941be08d24cc 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -518,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. /// @@ -530,7 +530,7 @@ 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. 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/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/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index 4ada1d72a0f8e..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; @@ -811,28 +822,36 @@ void main() { 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); - final String shorebirdYamlPath = fileSystem.path.join( - environment.buildDir.path, - 'App.framework', - 'Versions', - 'A', - 'Resources', - 'flutter_assets', - 'shorebird.yaml', - ); - 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 @@ -841,8 +860,21 @@ flavors: 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'); }, @@ -912,11 +944,13 @@ flavors: .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, @@ -926,6 +960,7 @@ flavors: 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, diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index d078b7fedd4fe..eebe3fef1a98a 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -942,7 +942,7 @@ void main() { 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']); @@ -1067,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. 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', From f2ee5328245c94bd90b06de85c8b11d9adecedf9 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 12 Dec 2025 14:50:17 -0800 Subject: [PATCH 083/105] chore: move build_engine scripts into this repo (#98) * chore: move build_engine scripts into this repo * chore: fix path of content_aware_hash.sh --- shorebird/ci/internal/generate_manifest.sh | 93 ++++++++++ shorebird/ci/internal/linux_build.sh | 105 +++++++++++ shorebird/ci/internal/linux_setup.sh | 30 +++ shorebird/ci/internal/linux_test_build.sh | 29 +++ shorebird/ci/internal/linux_upload.sh | 138 ++++++++++++++ shorebird/ci/internal/mac_build.sh | 204 +++++++++++++++++++++ shorebird/ci/internal/mac_setup.sh | 11 ++ shorebird/ci/internal/mac_upload.sh | 180 ++++++++++++++++++ shorebird/ci/internal/win_build.sh | 63 +++++++ shorebird/ci/internal/win_setup.sh | 8 + shorebird/ci/internal/win_upload.sh | 90 +++++++++ shorebird/ci/linux_build_and_upload.sh | 32 ++++ shorebird/ci/mac_build_and_upload.sh | 32 ++++ shorebird/ci/win_build_and_upload.sh | 32 ++++ 14 files changed, 1047 insertions(+) create mode 100755 shorebird/ci/internal/generate_manifest.sh create mode 100755 shorebird/ci/internal/linux_build.sh create mode 100755 shorebird/ci/internal/linux_setup.sh create mode 100755 shorebird/ci/internal/linux_test_build.sh create mode 100755 shorebird/ci/internal/linux_upload.sh create mode 100755 shorebird/ci/internal/mac_build.sh create mode 100755 shorebird/ci/internal/mac_setup.sh create mode 100755 shorebird/ci/internal/mac_upload.sh create mode 100755 shorebird/ci/internal/win_build.sh create mode 100755 shorebird/ci/internal/win_setup.sh create mode 100755 shorebird/ci/internal/win_upload.sh create mode 100755 shorebird/ci/linux_build_and_upload.sh create mode 100755 shorebird/ci/mac_build_and_upload.sh create mode 100755 shorebird/ci/win_build_and_upload.sh 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 From 19447bfb1d77b9ced3b6a15f6090517a389369fc Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 15 Dec 2025 16:55:22 -0800 Subject: [PATCH 084/105] chore: update to use new CreateGroupIsolate API (#99) * chore: roll dart to 6a78a2deaee05bc74775fcfa2ff27aa53c96efca * wip * chore: run et format * chore: attempt to clean up shorebird.cc * chore: fix build * chore: remove FLUTTER_STORAGE_BASE_URL override --- .github/workflows/shorebird_ci.yml | 5 -- DEPS | 2 +- engine/src/flutter/runtime/dart_isolate.cc | 31 +++++++++- .../runtime/dart_isolate_group_data.cc | 8 ++- .../flutter/runtime/dart_isolate_group_data.h | 8 ++- .../shell/common/shorebird/shorebird.cc | 61 +++++++++++++------ .../shell/common/shorebird/shorebird.h | 19 ++++++ 7 files changed, 106 insertions(+), 28 deletions(-) diff --git a/.github/workflows/shorebird_ci.yml b/.github/workflows/shorebird_ci.yml index 7b712b1583b87..9597d6a599344 100644 --- a/.github/workflows/shorebird_ci.yml +++ b/.github/workflows/shorebird_ci.yml @@ -21,11 +21,6 @@ jobs: name: 🐦 Shorebird Test - # TODO(eseidel): This is also set inside shorebird_tests, unclear if - # if it's needed here as well. - env: - FLUTTER_STORAGE_BASE_URL: https://download.shorebird.dev - steps: - name: 📚 Git Checkout uses: actions/checkout@v4 diff --git a/DEPS b/DEPS index e6f31dc15b8a5..cc85dc5695ff0 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "790993a4fb8ecf784de4e29532d75b027658f27e", + "dart_sdk_revision": "6a78a2deaee05bc74775fcfa2ff27aa53c96efca", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", diff --git a/engine/src/flutter/runtime/dart_isolate.cc b/engine/src/flutter/runtime/dart_isolate.cc index 521c284f1c905..3735cd03fcd0e 100644 --- a/engine/src/flutter/runtime/dart_isolate.cc +++ b/engine/src/flutter/runtime/dart_isolate.cc @@ -21,6 +21,10 @@ #include "flutter/runtime/isolate_configuration.h" #include "flutter/runtime/platform_isolate_manager.h" #include "fml/message_loop_task_queues.h" + +#if SHOREBIRD_USE_INTERPRETER +#include "flutter/shell/common/shorebird/shorebird.h" // nogncheck +#endif #include "fml/task_source.h" #include "fml/time/time_point.h" #include "third_party/dart/runtime/include/bin/native_assets_api.h" @@ -245,6 +249,12 @@ std::weak_ptr DartIsolate::CreateRootIsolate( } else { // The child isolate preparer is null but will be set when the isolate is // being prepared to run. +#if SHOREBIRD_USE_INTERPRETER + // Get the base snapshot for Shorebird linking support (may be null). + fml::RefPtr base_snapshot = GetBaseIsolateSnapshot(); +#else + fml::RefPtr base_snapshot = nullptr; +#endif isolate_group_data = std::make_unique>( std::shared_ptr(new DartIsolateGroupData( @@ -254,13 +264,30 @@ std::weak_ptr DartIsolate::CreateRootIsolate( context.advisory_script_entrypoint, // advisory entrypoint nullptr, // child isolate preparer isolate_create_callback, // isolate create callback - isolate_shutdown_callback, // isolate shutdown callback - std::move(native_assets_manager) // + isolate_shutdown_callback, // isolate shutdown callback + std::move(native_assets_manager), // native assets manager + std::move(base_snapshot) // base snapshot (Shorebird) ))); isolate_maker = [](std::shared_ptr* isolate_group_data, std::shared_ptr* isolate_data, Dart_IsolateFlags* flags, char** error) { +#if SHOREBIRD_USE_INTERPRETER + auto base_snapshot = (*isolate_group_data)->GetBaseSnapshot(); + if (base_snapshot) { + // Use the Shorebird API that accepts base snapshot for linking. + return Dart_CreateIsolateGroupWithBaseSnapshot( + (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), + (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), + (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(), + (*isolate_group_data) + ->GetIsolateSnapshot() + ->GetInstructionsMapping(), + base_snapshot->GetDataMapping(), + base_snapshot->GetInstructionsMapping(), flags, isolate_group_data, + isolate_data, error); + } +#endif return Dart_CreateIsolateGroup( (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), diff --git a/engine/src/flutter/runtime/dart_isolate_group_data.cc b/engine/src/flutter/runtime/dart_isolate_group_data.cc index 0e844d3e3c417..a8ecffee5b1ea 100644 --- a/engine/src/flutter/runtime/dart_isolate_group_data.cc +++ b/engine/src/flutter/runtime/dart_isolate_group_data.cc @@ -18,9 +18,11 @@ DartIsolateGroupData::DartIsolateGroupData( const ChildIsolatePreparer& child_isolate_preparer, const fml::closure& isolate_create_callback, const fml::closure& isolate_shutdown_callback, - std::shared_ptr native_assets_manager) + std::shared_ptr native_assets_manager, + fml::RefPtr base_snapshot) : settings_(settings), isolate_snapshot_(std::move(isolate_snapshot)), + base_snapshot_(std::move(base_snapshot)), advisory_script_uri_(std::move(advisory_script_uri)), advisory_script_entrypoint_(std::move(advisory_script_entrypoint)), child_isolate_preparer_(child_isolate_preparer), @@ -41,6 +43,10 @@ fml::RefPtr DartIsolateGroupData::GetIsolateSnapshot() return isolate_snapshot_; } +fml::RefPtr DartIsolateGroupData::GetBaseSnapshot() const { + return base_snapshot_; +} + const std::string& DartIsolateGroupData::GetAdvisoryScriptURI() const { return advisory_script_uri_; } diff --git a/engine/src/flutter/runtime/dart_isolate_group_data.h b/engine/src/flutter/runtime/dart_isolate_group_data.h index 8ff29272150ab..1502b2fc8e290 100644 --- a/engine/src/flutter/runtime/dart_isolate_group_data.h +++ b/engine/src/flutter/runtime/dart_isolate_group_data.h @@ -39,7 +39,8 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { const ChildIsolatePreparer& child_isolate_preparer, const fml::closure& isolate_create_callback, const fml::closure& isolate_shutdown_callback, - std::shared_ptr native_assets_manager = nullptr); + std::shared_ptr native_assets_manager = nullptr, + fml::RefPtr base_snapshot = nullptr); ~DartIsolateGroupData(); @@ -47,6 +48,10 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { fml::RefPtr GetIsolateSnapshot() const; + /// Returns the base snapshot for Shorebird linking support. + /// May be null if not using Shorebird or if no patch is active. + fml::RefPtr GetBaseSnapshot() const; + const std::string& GetAdvisoryScriptURI() const; const std::string& GetAdvisoryScriptEntrypoint() const; @@ -81,6 +86,7 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { std::vector> kernel_buffers_; const Settings settings_; const fml::RefPtr isolate_snapshot_; + const fml::RefPtr base_snapshot_; const std::string advisory_script_uri_; const std::string advisory_script_entrypoint_; mutable std::mutex child_isolate_preparer_mutex_; diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index ec2bc6bf3c9cd..8cb32cfc9916b 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -45,24 +45,38 @@ extern "C" __attribute__((weak)) unsigned long getauxval(unsigned long type) { } #endif -// TODO(eseidel): I believe we need to leak these or we'll sometimes crash -// when using the base snapshot in mixed mode. This likely will not play -// nicely with multi-engine support and will need to be refactored. +#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. +// 3. GetBaseIsolateSnapshot() returns the isolate snapshot for use when +// creating isolate groups with Dart_CreateIsolateGroupWithBaseSnapshot(), +// which needs the base snapshot for linking patched code. +// +// 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. +void StoreBaseSnapshots(Settings& settings) { + // Create DartSnapshot objects that hold references to the symbol mappings + // in the App.framework. The snapshots are static data in the framework, + // but we need DartSnapshot objects to keep the NativeLibrary refs 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()); } +fml::RefPtr GetBaseIsolateSnapshot() { + return isolate_snapshot; +} + +#endif // SHOREBIRD_USE_INTERPRETER + class FileCallbacksImpl { public: static void* Open(); @@ -104,7 +118,9 @@ std::string GetValueFromYaml(const std::string& yaml, const std::string& key) { return ""; } -// FIXME: consolidate this with the other ConfigureShorebird +/// Newer api, used by Desktop implementations. +/// Does not directly manipulate Settings. +// FIXME: Consolidate this with the other ConfigureShorebird() API. bool ConfigureShorebird(const ShorebirdConfigArgs& args, std::string& patch_path) { patch_path = fml::PathToUtf8(args.release_app_library_path); @@ -201,6 +217,8 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, return true; } +/// Older api used by iOS and Android, directly manipulates Settings. +// FIXME: Consolidate this with the other ConfigureShorebird() API. void ConfigureShorebird(std::string code_cache_path, std::string app_storage_path, Settings& settings, @@ -251,15 +269,14 @@ void ConfigureShorebird(std::string code_cache_path, shorebird_yaml.c_str()); } - // We've decided not to support synchronous updates on launch for now. - // It's a terrible user experience (having the app hang on launch) and - // instead we will provide examples of how to build a custom update UI - // within Dart, including updating as part of login, etc. + // 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. + // We store the base snapshot on iOS for use when creating the isolate group. #if SHOREBIRD_USE_INTERPRETER - SetBaseSnapshot(settings); + StoreBaseSnapshots(settings); #endif shorebird_validate_next_boot_patch(); @@ -312,9 +329,17 @@ void ConfigureShorebird(std::string code_cache_path, } 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, diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.h b/engine/src/flutter/shell/common/shorebird/shorebird.h index c6873c5014a00..50c6f59e1fa60 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.h +++ b/engine/src/flutter/shell/common/shorebird/shorebird.h @@ -2,15 +2,22 @@ #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; @@ -30,9 +37,12 @@ struct ShorebirdConfigArgs { 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, @@ -40,8 +50,17 @@ void ConfigureShorebird(std::string code_cache_path, 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); +#if SHOREBIRD_USE_INTERPRETER +/// Returns the base isolate snapshot for Shorebird linking support. +/// Must be called after ConfigureShorebird() has stored the base snapshots. +/// May return null if not using Shorebird interpreter mode. +fml::RefPtr GetBaseIsolateSnapshot(); +#endif // SHOREBIRD_USE_INTERPRETER + } // namespace flutter #endif // FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ From dc935e35f8918e87380f505e96c01520df09e34e Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Fri, 19 Dec 2025 13:18:34 -0500 Subject: [PATCH 085/105] bump updater rev --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index cc85dc5695ff0..fc4060011e5ee 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { "dart_sdk_revision": "6a78a2deaee05bc74775fcfa2ff27aa53c96efca", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", - "updater_rev": "76f005940db57c38b479cee858abc0cfbd12ac28", + "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 5056ba9387dd1081fe277cd0d5f06db6cc34ac0f Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Tue, 30 Dec 2025 16:10:40 -0800 Subject: [PATCH 086/105] fix: crash after patching on iOS --- engine/src/flutter/runtime/dart_isolate.cc | 20 +++++++++- shorebird/docs/BUILDING.md | 44 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 shorebird/docs/BUILDING.md diff --git a/engine/src/flutter/runtime/dart_isolate.cc b/engine/src/flutter/runtime/dart_isolate.cc index 3735cd03fcd0e..c1e4fb5911f48 100644 --- a/engine/src/flutter/runtime/dart_isolate.cc +++ b/engine/src/flutter/runtime/dart_isolate.cc @@ -1135,7 +1135,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 + parent_group_data.GetBaseSnapshot()))); TaskRunners null_task_runners(advisory_script_uri, /* platform= */ nullptr, @@ -1157,6 +1159,22 @@ Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback( [](std::shared_ptr* isolate_group_data, std::shared_ptr* isolate_data, Dart_IsolateFlags* flags, char** error) { +#if SHOREBIRD_USE_INTERPRETER + auto base_snapshot = (*isolate_group_data)->GetBaseSnapshot(); + if (base_snapshot) { + // Use the Shorebird API that accepts base snapshot for linking. + return Dart_CreateIsolateGroupWithBaseSnapshot( + (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), + (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), + (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(), + (*isolate_group_data) + ->GetIsolateSnapshot() + ->GetInstructionsMapping(), + base_snapshot->GetDataMapping(), + base_snapshot->GetInstructionsMapping(), flags, + isolate_group_data, isolate_data, error); + } +#endif return Dart_CreateIsolateGroup( (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), 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 +``` From 5e6243bad7e0be75f5c6108e44b6f024ec0629a5 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 5 Jan 2026 16:53:37 -0800 Subject: [PATCH 087/105] fix: revert to using Shorebird_SetBaseSnapshots to stop iOS crashers --- DEPS | 2 +- engine/src/flutter/runtime/dart_isolate.cc | 51 ++----------------- .../runtime/dart_isolate_group_data.cc | 8 +-- .../flutter/runtime/dart_isolate_group_data.h | 8 +-- .../flutter/runtime/shorebird/patch_cache.cc | 7 ++- .../shell/common/shorebird/shorebird.cc | 38 ++++++-------- .../shell/common/shorebird/shorebird.h | 7 --- 7 files changed, 26 insertions(+), 95 deletions(-) diff --git a/DEPS b/DEPS index fc4060011e5ee..6125737980cf0 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "6a78a2deaee05bc74775fcfa2ff27aa53c96efca", + "dart_sdk_revision": "16063abdb2459d8c2054822355e906dce4cdce91", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", diff --git a/engine/src/flutter/runtime/dart_isolate.cc b/engine/src/flutter/runtime/dart_isolate.cc index c1e4fb5911f48..c81ab7c7bd44d 100644 --- a/engine/src/flutter/runtime/dart_isolate.cc +++ b/engine/src/flutter/runtime/dart_isolate.cc @@ -21,10 +21,6 @@ #include "flutter/runtime/isolate_configuration.h" #include "flutter/runtime/platform_isolate_manager.h" #include "fml/message_loop_task_queues.h" - -#if SHOREBIRD_USE_INTERPRETER -#include "flutter/shell/common/shorebird/shorebird.h" // nogncheck -#endif #include "fml/task_source.h" #include "fml/time/time_point.h" #include "third_party/dart/runtime/include/bin/native_assets_api.h" @@ -249,12 +245,6 @@ std::weak_ptr DartIsolate::CreateRootIsolate( } else { // The child isolate preparer is null but will be set when the isolate is // being prepared to run. -#if SHOREBIRD_USE_INTERPRETER - // Get the base snapshot for Shorebird linking support (may be null). - fml::RefPtr base_snapshot = GetBaseIsolateSnapshot(); -#else - fml::RefPtr base_snapshot = nullptr; -#endif isolate_group_data = std::make_unique>( std::shared_ptr(new DartIsolateGroupData( @@ -264,30 +254,13 @@ std::weak_ptr DartIsolate::CreateRootIsolate( context.advisory_script_entrypoint, // advisory entrypoint nullptr, // child isolate preparer isolate_create_callback, // isolate create callback - isolate_shutdown_callback, // isolate shutdown callback - std::move(native_assets_manager), // native assets manager - std::move(base_snapshot) // base snapshot (Shorebird) + isolate_shutdown_callback, // isolate shutdown callback + std::move(native_assets_manager) // ))); isolate_maker = [](std::shared_ptr* isolate_group_data, std::shared_ptr* isolate_data, Dart_IsolateFlags* flags, char** error) { -#if SHOREBIRD_USE_INTERPRETER - auto base_snapshot = (*isolate_group_data)->GetBaseSnapshot(); - if (base_snapshot) { - // Use the Shorebird API that accepts base snapshot for linking. - return Dart_CreateIsolateGroupWithBaseSnapshot( - (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), - (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), - (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(), - (*isolate_group_data) - ->GetIsolateSnapshot() - ->GetInstructionsMapping(), - base_snapshot->GetDataMapping(), - base_snapshot->GetInstructionsMapping(), flags, isolate_group_data, - isolate_data, error); - } -#endif return Dart_CreateIsolateGroup( (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), @@ -1136,8 +1109,8 @@ Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback( parent_group_data.GetChildIsolatePreparer(), parent_group_data.GetIsolateCreateCallback(), parent_group_data.GetIsolateShutdownCallback(), - nullptr, // native_assets_manager - parent_group_data.GetBaseSnapshot()))); + nullptr // native_assets_manager + ))); TaskRunners null_task_runners(advisory_script_uri, /* platform= */ nullptr, @@ -1159,22 +1132,6 @@ Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback( [](std::shared_ptr* isolate_group_data, std::shared_ptr* isolate_data, Dart_IsolateFlags* flags, char** error) { -#if SHOREBIRD_USE_INTERPRETER - auto base_snapshot = (*isolate_group_data)->GetBaseSnapshot(); - if (base_snapshot) { - // Use the Shorebird API that accepts base snapshot for linking. - return Dart_CreateIsolateGroupWithBaseSnapshot( - (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), - (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), - (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(), - (*isolate_group_data) - ->GetIsolateSnapshot() - ->GetInstructionsMapping(), - base_snapshot->GetDataMapping(), - base_snapshot->GetInstructionsMapping(), flags, - isolate_group_data, isolate_data, error); - } -#endif return Dart_CreateIsolateGroup( (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), diff --git a/engine/src/flutter/runtime/dart_isolate_group_data.cc b/engine/src/flutter/runtime/dart_isolate_group_data.cc index a8ecffee5b1ea..0e844d3e3c417 100644 --- a/engine/src/flutter/runtime/dart_isolate_group_data.cc +++ b/engine/src/flutter/runtime/dart_isolate_group_data.cc @@ -18,11 +18,9 @@ DartIsolateGroupData::DartIsolateGroupData( const ChildIsolatePreparer& child_isolate_preparer, const fml::closure& isolate_create_callback, const fml::closure& isolate_shutdown_callback, - std::shared_ptr native_assets_manager, - fml::RefPtr base_snapshot) + std::shared_ptr native_assets_manager) : settings_(settings), isolate_snapshot_(std::move(isolate_snapshot)), - base_snapshot_(std::move(base_snapshot)), advisory_script_uri_(std::move(advisory_script_uri)), advisory_script_entrypoint_(std::move(advisory_script_entrypoint)), child_isolate_preparer_(child_isolate_preparer), @@ -43,10 +41,6 @@ fml::RefPtr DartIsolateGroupData::GetIsolateSnapshot() return isolate_snapshot_; } -fml::RefPtr DartIsolateGroupData::GetBaseSnapshot() const { - return base_snapshot_; -} - const std::string& DartIsolateGroupData::GetAdvisoryScriptURI() const { return advisory_script_uri_; } diff --git a/engine/src/flutter/runtime/dart_isolate_group_data.h b/engine/src/flutter/runtime/dart_isolate_group_data.h index 1502b2fc8e290..8ff29272150ab 100644 --- a/engine/src/flutter/runtime/dart_isolate_group_data.h +++ b/engine/src/flutter/runtime/dart_isolate_group_data.h @@ -39,8 +39,7 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { const ChildIsolatePreparer& child_isolate_preparer, const fml::closure& isolate_create_callback, const fml::closure& isolate_shutdown_callback, - std::shared_ptr native_assets_manager = nullptr, - fml::RefPtr base_snapshot = nullptr); + std::shared_ptr native_assets_manager = nullptr); ~DartIsolateGroupData(); @@ -48,10 +47,6 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { fml::RefPtr GetIsolateSnapshot() const; - /// Returns the base snapshot for Shorebird linking support. - /// May be null if not using Shorebird or if no patch is active. - fml::RefPtr GetBaseSnapshot() const; - const std::string& GetAdvisoryScriptURI() const; const std::string& GetAdvisoryScriptEntrypoint() const; @@ -86,7 +81,6 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage { std::vector> kernel_buffers_; const Settings settings_; const fml::RefPtr isolate_snapshot_; - const fml::RefPtr base_snapshot_; const std::string advisory_script_uri_; const std::string advisory_script_entrypoint_; mutable std::mutex child_isolate_preparer_mutex_; diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.cc b/engine/src/flutter/runtime/shorebird/patch_cache.cc index 30c99aea3a011..d3dbe617ebfea 100644 --- a/engine/src/flutter/runtime/shorebird/patch_cache.cc +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -45,10 +45,9 @@ std::shared_ptr PatchCacheEntry::Create( 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, - /* load as read-only, not rx */ false); + 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; diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index 8cb32cfc9916b..9a4136b48bbe6 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -46,7 +46,6 @@ extern "C" __attribute__((weak)) unsigned long getauxval(unsigned long type) { #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 @@ -54,27 +53,23 @@ extern "C" __attribute__((weak)) unsigned long getauxval(unsigned long type) { // data for patch generation/validation. // 2. The base snapshots are immutable (baked into the IPA) so sharing them // across isolate groups is safe. -// 3. GetBaseIsolateSnapshot() returns the isolate snapshot for use when -// creating isolate groups with Dart_CreateIsolateGroupWithBaseSnapshot(), -// which needs the base snapshot for linking patched code. // // 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 StoreBaseSnapshots(Settings& settings) { - // Create DartSnapshot objects that hold references to the symbol mappings - // in the App.framework. The snapshots are static data in the framework, - // but we need DartSnapshot objects to keep the NativeLibrary refs alive. +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()); } - -fml::RefPtr GetBaseIsolateSnapshot() { - return isolate_snapshot; -} - #endif // SHOREBIRD_USE_INTERPRETER class FileCallbacksImpl { @@ -120,7 +115,7 @@ std::string GetValueFromYaml(const std::string& yaml, const std::string& key) { /// Newer api, used by Desktop implementations. /// Does not directly manipulate Settings. -// FIXME: Consolidate this with the other ConfigureShorebird() API. +// TODO(eseidel): Consolidate this with the other ConfigureShorebird() API. bool ConfigureShorebird(const ShorebirdConfigArgs& args, std::string& patch_path) { patch_path = fml::PathToUtf8(args.release_app_library_path); @@ -170,10 +165,9 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, args.shorebird_yaml.c_str()); } - // We've decided not to support synchronous updates on launch for now. - // It's a terrible user experience (having the app hang on launch) and - // instead we will provide examples of how to build a custom update UI - // within Dart, including updating as part of login, etc. + // 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"; @@ -218,7 +212,7 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, } /// Older api used by iOS and Android, directly manipulates Settings. -// FIXME: Consolidate this with the other ConfigureShorebird() API. +// TODO(eseidel): Consolidate this with the other ConfigureShorebird() API. void ConfigureShorebird(std::string code_cache_path, std::string app_storage_path, Settings& settings, @@ -274,9 +268,9 @@ void ConfigureShorebird(std::string code_cache_path, // package:shorebird_code_push. // https://github.com/shorebirdtech/shorebird/issues/950 - // We store the base snapshot on iOS for use when creating the isolate group. + // We only set the base snapshot on iOS for now. #if SHOREBIRD_USE_INTERPRETER - StoreBaseSnapshots(settings); + SetBaseSnapshot(settings); #endif shorebird_validate_next_boot_patch(); @@ -334,7 +328,7 @@ void* FileCallbacksImpl::Open() { *isolate_snapshot) .release(); #else - // SnapshotsDataHandle exists on all platforms (for testing)but is only used + // 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. diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.h b/engine/src/flutter/shell/common/shorebird/shorebird.h index 50c6f59e1fa60..ab5c9162ea0f2 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.h +++ b/engine/src/flutter/shell/common/shorebird/shorebird.h @@ -54,13 +54,6 @@ void ConfigureShorebird(std::string code_cache_path, /// Exposed for testing. std::string GetValueFromYaml(const std::string& yaml, const std::string& key); -#if SHOREBIRD_USE_INTERPRETER -/// Returns the base isolate snapshot for Shorebird linking support. -/// Must be called after ConfigureShorebird() has stored the base snapshots. -/// May return null if not using Shorebird interpreter mode. -fml::RefPtr GetBaseIsolateSnapshot(); -#endif // SHOREBIRD_USE_INTERPRETER - } // namespace flutter #endif // FLUTTER_SHELL_COMMON_SHOREBIRD_SHOREBIRD_H_ From 16e056bf949d488fd1e84b0cb92b209226bd0af1 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 5 Jan 2026 17:14:07 -0800 Subject: [PATCH 088/105] chore: roll dart to 6912e58e9ab422a51173039f2b04088db0e62b98 to fix linux --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6125737980cf0..d56448a75d2ce 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "16063abdb2459d8c2054822355e906dce4cdce91", + "dart_sdk_revision": "6912e58e9ab422a51173039f2b04088db0e62b98", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", From 62ca81d1cac674fcb520d979a8232b336ade7e56 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 5 Jan 2026 17:32:39 -0800 Subject: [PATCH 089/105] chore: roll Dart to fix 6dbdbe02de04f8fb193f4763a018d7f67e840c10 --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index d56448a75d2ce..d10e1ee545072 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "6912e58e9ab422a51173039f2b04088db0e62b98", + "dart_sdk_revision": "6dbdbe02de04f8fb193f4763a018d7f67e840c10", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", From 1592b16e0613cbe0ce120799888b6c1da6a35494 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 8 Jan 2026 15:56:38 -0800 Subject: [PATCH 090/105] chore: roll dart to 3.10.7 2b8f13770fa72a8ef56b1406f873ee900c45ec2e --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index d10e1ee545072..f9420d716b996 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', 'skia_revision': 'ea7cdbc6b986bbefcbac92fa429782e59518510f', - "dart_sdk_revision": "6dbdbe02de04f8fb193f4763a018d7f67e840c10", + "dart_sdk_revision": "2b8f13770fa72a8ef56b1406f873ee900c45ec2e", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", From ec38d1b3cd27f04685c5fb0d87c2c650cb27cebc Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 8 Jan 2026 16:15:45 -0800 Subject: [PATCH 091/105] chore: fix linux --- engine/src/flutter/shell/common/shorebird/shorebird.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index 9a4136b48bbe6..81469a480f735 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -118,7 +118,7 @@ std::string GetValueFromYaml(const std::string& yaml, const std::string& key) { // TODO(eseidel): Consolidate this with the other ConfigureShorebird() API. bool ConfigureShorebird(const ShorebirdConfigArgs& args, std::string& patch_path) { - patch_path = fml::PathToUtf8(args.release_app_library_path); + patch_path = args.release_app_library_path; auto shorebird_updater_dir_name = "shorebird_updater"; // Parse app id from shorebird.yaml From af7e87e130b5710a8b3024876173f22bed7e56ac Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 8 Jan 2026 19:25:16 -0800 Subject: [PATCH 092/105] chore: roll engine to 6062c68600c53ff4e1fecf3ce79157ef4ce33000 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 061f1493f9cc0..196d7fccb2f5a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -78fc3012e45889657f72359b005af7beac47ba3d +6062c68600c53ff4e1fecf3ce79157ef4ce33000 \ No newline at end of file From 6aa0b8e1dfda71b93947c9312e69b016729ecfc5 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Sun, 11 Jan 2026 15:06:13 -0800 Subject: [PATCH 093/105] feat: add support for patch_verification_mode (#100) * feat: allow patch_verification_mode * test: update tests * chore: rename to patch_verification --- packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart | 1 + .../test/general.shard/shorebird/shorebird_yaml_test.dart | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart index 9e40f392b7eb8..a741b2683d765 100644 --- a/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart +++ b/packages/flutter_tools/lib/src/shorebird/shorebird_yaml.dart @@ -56,6 +56,7 @@ Map compileShorebirdYaml(YamlMap yamlMap, {required String? fla } copyIfSet('base_url'); copyIfSet('auto_update'); + copyIfSet('patch_verification'); final String? shorebirdPublicKeyEnvVar = environment['SHOREBIRD_PUBLIC_KEY']; if (shorebirdPublicKeyEnvVar != null) { compiled['patch_public_key'] = shorebirdPublicKeyEnvVar; 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 index 602de37681555..7e05fec171409 100644 --- a/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart +++ b/packages/flutter_tools/test/general.shard/shorebird/shorebird_yaml_test.dart @@ -52,6 +52,7 @@ 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; @@ -61,6 +62,7 @@ base_url: https://example.com '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'}); @@ -68,6 +70,7 @@ base_url: https://example.com 'app_id': '2-a', 'auto_update': false, 'base_url': 'https://example.com', + 'patch_verification': 'strict', 'patch_public_key': '4-a', }); }); From 7e827a7cd7f47b31dc5995b1f31baa837c6ca09e Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Sun, 11 Jan 2026 15:07:00 -0800 Subject: [PATCH 094/105] chore: roll updater to 8691c8f60e69f8eb1f35361f4a22e8c9a7fdf93c to include patch_verification option --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f9420d716b996..f9ca7b8736e8d 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { "dart_sdk_revision": "2b8f13770fa72a8ef56b1406f873ee900c45ec2e", "dart_sdk_git": "git@github.com:shorebirdtech/dart-sdk.git", "updater_git": "https://github.com/shorebirdtech/updater.git", - "updater_rev": "9db198a6344f7b9ec2843e06a459938a520e314f", + "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. From a1f5cc9af8c500fbeca1a1aade8226a2c2a4dc0c Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Sun, 11 Jan 2026 20:41:33 -0800 Subject: [PATCH 095/105] chore: roll engine to b4ada61596b3281a9e156b747f69b761a8489bbd --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 196d7fccb2f5a..76385233df65f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6062c68600c53ff4e1fecf3ce79157ef4ce33000 \ No newline at end of file +b4ada61596b3281a9e156b747f69b761a8489bbd \ No newline at end of file From 6c43b70267a27cd42efac09ca534f9086a39be2c Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 16 Jan 2026 15:54:23 -0800 Subject: [PATCH 096/105] chore: roll engine to a1f5cc9af8c500fbeca1a1aade8226a2c2a4dc0c --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 76385233df65f..cc2c1f4c2baaf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b4ada61596b3281a9e156b747f69b761a8489bbd \ No newline at end of file +a1f5cc9af8c500fbeca1a1aade8226a2c2a4dc0c \ No newline at end of file From 9ec97995930ec55f111a703f2ad9a3631ca7aa82 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 22 Jan 2026 22:20:15 -0800 Subject: [PATCH 097/105] fix: use of FlutterEngineGroup breaks patching (#101) * es/report_start_fix * fix: second callsite --- engine/src/flutter/runtime/shorebird/BUILD.gn | 5 +++ .../flutter/runtime/shorebird/patch_cache.cc | 14 +++++++ .../shell/common/shorebird/shorebird.cc | 39 +++++-------------- 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/engine/src/flutter/runtime/shorebird/BUILD.gn b/engine/src/flutter/runtime/shorebird/BUILD.gn index facee07ba5cd1..81bf3f588b3f8 100644 --- a/engine/src/flutter/runtime/shorebird/BUILD.gn +++ b/engine/src/flutter/runtime/shorebird/BUILD.gn @@ -12,4 +12,9 @@ source_set("patch_cache") { "//flutter/fml", "//flutter/runtime:libdart", ] + + # For shorebird_report_launch_start() in updater.h + # The include path "third_party/updater/library/include/updater.h" is relative + # to //flutter/, which is already in the default include path. + include_dirs = [ "//flutter" ] } diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.cc b/engine/src/flutter/runtime/shorebird/patch_cache.cc index d3dbe617ebfea..5610eb3393d60 100644 --- a/engine/src/flutter/runtime/shorebird/patch_cache.cc +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -4,9 +4,12 @@ #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/updater/library/include/updater.h" namespace flutter { @@ -148,7 +151,18 @@ std::shared_ptr TryLoadFromPatch( FML_LOG(INFO) << "Loading symbol from patch: " << symbol_name; + // Report launch_start when we're actually about to use a patch. + // This is called at exactly the right time - right before the patched + // snapshot is loaded. We use std::once_flag to ensure it's only called + // once per process, and only for the first symbol (isolate data). + // This fixes the FlutterEngineGroup issue where report_launch_start was + // called too early (in ConfigureShorebird) before any patch was used. + static std::once_flag launch_start_flag; if (symbol == kIsolateDataSymbol) { + std::call_once(launch_start_flag, []() { + FML_LOG(INFO) << "Reporting launch start for patch"; + shorebird_report_launch_start(); + }); return PatchMapping::CreateIsolateData(cache_entry); } else { FML_CHECK(symbol == kIsolateInstructionsSymbol); diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index 81469a480f735..d040e07e0285d 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -181,25 +181,14 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, FML_LOG(INFO) << "Shorebird updater: no active patch."; } - // We are careful only to report a launch start in the case where it's the - // first time we've configured shorebird this process. Otherwise we could end - // up in a case where we report a launch start, but never a completion (e.g. - // from package:flutter_work_manager which sometimes creates a FlutterEngine - // (and thus configures shorebird) but never runs it. The proper fix for this - // is probably to move the launch_start() call to be later in the lifecycle - // (when the snapshot is loaded and run, rather than when FlutterEngine is - // initialized). This "hack" will still have a problem where FlutterEngine is - // initialized but never run before the app is quit, could still cause us to - // suddenly mark-bad a patch that was never actually attempted to launch. + // 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; } - // Once start_update_thread is called, the next_boot_patch* functions may - // change their return values if the shorebird_report_launch_failed - // function is called. - shorebird_report_launch_start(); - if (shorebird_should_auto_update()) { FML_LOG(INFO) << "Starting Shorebird update"; shorebird_start_update_thread(); @@ -294,25 +283,15 @@ void ConfigureShorebird(std::string code_cache_path, FML_LOG(INFO) << "Shorebird updater: no active patch."; } - // We are careful only to report a launch start in the case where it's the - // first time we've configured shorebird this process. Otherwise we could end - // up in a case where we report a launch start, but never a completion (e.g. - // from package:flutter_work_manager which sometimes creates a FlutterEngine - // (and thus configures shorebird) but never runs it. The proper fix for this - // is probably to move the launch_start() call to be later in the lifecycle - // (when the snapshot is loaded and run, rather than when FlutterEngine is - // initialized). This "hack" will still have a problem where FlutterEngine is - // initialized but never run before the app is quit, could still cause us to - // suddenly mark-bad a patch that was never actually attempted to launch. + // 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; } - // Once start_update_thread is called, the next_boot_patch* functions may - // change their return values if the shorebird_report_launch_failed - // function is called. - shorebird_report_launch_start(); - if (shorebird_should_auto_update()) { FML_LOG(INFO) << "Starting Shorebird update"; shorebird_start_update_thread(); From e87b9b5fe23bde14ae510340908d47729be6c049 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 23 Jan 2026 14:13:57 -0800 Subject: [PATCH 098/105] chore: roll engine to 9ec97995930ec55f111a703f2ad9a3631ca7aa82 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cc2c1f4c2baaf..418e37e7e44ae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a1f5cc9af8c500fbeca1a1aade8226a2c2a4dc0c \ No newline at end of file +9ec97995930ec55f111a703f2ad9a3631ca7aa82 \ No newline at end of file From 50b8af000ba26227acfba511ab40d9199c102625 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 23 Jan 2026 15:30:24 -0800 Subject: [PATCH 099/105] chore: add a C++ interface onto the updater (#102) * chore: add a C++ interface onto the updater * chore: centralize SHOREBIRD_PLATFORM_SUPPORTED * test: fix tests --- engine/src/flutter/runtime/shorebird/BUILD.gn | 6 +- .../flutter/runtime/shorebird/patch_cache.cc | 5 +- engine/src/flutter/shell/common/BUILD.gn | 29 +-- engine/src/flutter/shell/common/shell.cc | 11 +- .../flutter/shell/common/shell_unittests.cc | 62 ++++++ .../flutter/shell/common/shorebird/BUILD.gn | 57 +++++- .../shell/common/shorebird/shorebird.cc | 103 ++++------ .../flutter/shell/common/shorebird/updater.cc | 166 +++++++++++++++ .../flutter/shell/common/shorebird/updater.h | 191 ++++++++++++++++++ .../common/shorebird/updater_unittests.cc | 127 ++++++++++++ .../flutter/shell/platform/android/BUILD.gn | 13 -- .../shell/platform/android/flutter_main.cc | 2 - .../shell/platform/darwin/ios/BUILD.gn | 8 - 13 files changed, 647 insertions(+), 133 deletions(-) create mode 100644 engine/src/flutter/shell/common/shorebird/updater.cc create mode 100644 engine/src/flutter/shell/common/shorebird/updater.h create mode 100644 engine/src/flutter/shell/common/shorebird/updater_unittests.cc diff --git a/engine/src/flutter/runtime/shorebird/BUILD.gn b/engine/src/flutter/runtime/shorebird/BUILD.gn index 81bf3f588b3f8..1f856e36d3f48 100644 --- a/engine/src/flutter/runtime/shorebird/BUILD.gn +++ b/engine/src/flutter/runtime/shorebird/BUILD.gn @@ -11,10 +11,6 @@ source_set("patch_cache") { deps = [ "//flutter/fml", "//flutter/runtime:libdart", + "//flutter/shell/common/shorebird:updater", ] - - # For shorebird_report_launch_start() in updater.h - # The include path "third_party/updater/library/include/updater.h" is relative - # to //flutter/, which is already in the default include path. - include_dirs = [ "//flutter" ] } diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.cc b/engine/src/flutter/runtime/shorebird/patch_cache.cc index 5610eb3393d60..b835d01b98639 100644 --- a/engine/src/flutter/runtime/shorebird/patch_cache.cc +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -9,7 +9,8 @@ #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "flutter/runtime/shorebird/patch_mapping.h" -#include "third_party/updater/library/include/updater.h" +#include "flutter/shell/common/shorebird/updater.h" +#include "third_party/dart/runtime/include/dart_api.h" namespace flutter { @@ -161,7 +162,7 @@ std::shared_ptr TryLoadFromPatch( if (symbol == kIsolateDataSymbol) { std::call_once(launch_start_flag, []() { FML_LOG(INFO) << "Reporting launch start for patch"; - shorebird_report_launch_start(); + shorebird::Updater::Instance().ReportLaunchStart(); }); return PatchMapping::CreateIsolateData(cache_entry); } else { diff --git a/engine/src/flutter/shell/common/BUILD.gn b/engine/src/flutter/shell/common/BUILD.gn index 45d48d8ac8873..11af400ec6290 100644 --- a/engine/src/flutter/shell/common/BUILD.gn +++ b/engine/src/flutter/shell/common/BUILD.gn @@ -148,13 +148,12 @@ 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", ] - include_dirs = [ "//flutter/updater" ] - if (impeller_supports_rendering) { sources += [ "snapshot_controller_impeller.cc", @@ -163,31 +162,6 @@ source_set("common") { deps += [ "//flutter/impeller" ] } - - # Needed to compile flutter_tester for macOS. - if (host_os == "mac" && target_os == "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" ] - } - } - - # Needed to compile flutter_tester for Windows. - if (host_os == "win" && target_os == "win") { - if (target_cpu == "x64") { - libs = [ - "userenv.lib", - "//flutter/third_party/updater/target/x86_64-pc-windows-msvc/release/updater.lib", - ] - } - } - - if (host_os == "linux" && target_os == "linux") { - if (target_cpu == "x64") { - libs = [ "//flutter/third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a" ] - } - } } # These are in their own source_set to avoid a dependency cycle with //common/graphics @@ -364,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 662a0f8393491..cb523c5985d44 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -46,7 +46,7 @@ #include "third_party/skia/include/core/SkGraphics.h" #include "third_party/tonic/common/log.h" -#include "third_party/updater/library/include/updater.h" +#include "flutter/shell/common/shorebird/updater.h" namespace flutter { @@ -523,14 +523,13 @@ Shell::Shell(DartVMRef vm, is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)), weak_factory_gpu_(nullptr), weak_factory_(this) { - // FIXME: This is probably the wrong place to hook into. -#if SHOREBIRD_PLATFORM_SUPPORTED + // Report launch status to Shorebird updater for crash recovery tracking. + // On unsupported platforms, NoOpUpdater handles these calls gracefully. if (!vm_) { - shorebird_report_launch_failure(); + shorebird::Updater::Instance().ReportLaunchFailure(); } else { - shorebird_report_launch_success(); + shorebird::Updater::Instance().ReportLaunchSuccess(); } -#endif 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..6bb7907b3936e 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,66 @@ TEST_F(ShellTest, ShoulDiscardLayerTreeIfFrameIsSizedIncorrectly) { DestroyShell(std::move(shell), task_runners); } +// Test that Shell creation triggers the Shorebird Updater's ReportLaunchSuccess +// call. This is important for the crash recovery mechanism to work correctly. +TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessOnShellCreation) { + // Install a mock updater before creating the shell + auto mock = std::make_unique(); + auto* mock_ptr = mock.get(); + shorebird::Updater::SetInstanceForTesting(std::move(mock)); + + EXPECT_EQ(mock_ptr->launch_success_count(), 0); + EXPECT_EQ(mock_ptr->launch_failure_count(), 0); + + auto settings = CreateSettingsForFixture(); + auto task_runners = GetTaskRunnersForFixture(); + auto shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + // Shell constructor should have called ReportLaunchSuccess + EXPECT_EQ(mock_ptr->launch_success_count(), 1); + EXPECT_EQ(mock_ptr->launch_failure_count(), 0); + + // Verify the call was logged + const auto& log = mock_ptr->call_log(); + EXPECT_TRUE(std::find(log.begin(), log.end(), "ReportLaunchSuccess") != + log.end()); + + DestroyShell(std::move(shell), task_runners); + + // Clean up - reset the updater instance + shorebird::Updater::ResetInstanceForTesting(); +} + +// Test that creating multiple shells only calls ReportLaunchSuccess for each +// shell. This verifies that each Shell reports its own launch status. +TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessForMultipleShells) { + auto mock = std::make_unique(); + auto* mock_ptr = mock.get(); + shorebird::Updater::SetInstanceForTesting(std::move(mock)); + + EXPECT_EQ(mock_ptr->launch_success_count(), 0); + + auto settings = CreateSettingsForFixture(); + + // Create first shell + auto task_runners1 = GetTaskRunnersForFixture(); + auto shell1 = CreateShell(settings, task_runners1); + ASSERT_TRUE(shell1); + EXPECT_EQ(mock_ptr->launch_success_count(), 1); + + // Create second shell + auto task_runners2 = GetTaskRunnersForFixture(); + auto shell2 = CreateShell(settings, task_runners2); + ASSERT_TRUE(shell2); + EXPECT_EQ(mock_ptr->launch_success_count(), 2); + + DestroyShell(std::move(shell1), task_runners1); + DestroyShell(std::move(shell2), task_runners2); + + 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 index dc2fc5515bd7c..2b1e29c03512d 100644 --- a/engine/src/flutter/shell/common/shorebird/BUILD.gn +++ b/engine/src/flutter/shell/common/shorebird/BUILD.gn @@ -15,6 +15,56 @@ source_set("snapshots_data_handle") { ] } +# 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", @@ -23,14 +73,13 @@ source_set("shorebird") { deps = [ ":snapshots_data_handle", + ":updater", "//flutter/fml", "//flutter/runtime", "//flutter/runtime:libdart", "//flutter/shell/common", "//flutter/shell/platform/embedder:embedder_headers", ] - - include_dirs = [ "//flutter/updater" ] } if (enable_unittests) { @@ -45,14 +94,14 @@ if (enable_unittests) { "patch_cache_unittests.cc", "shorebird_unittests.cc", "snapshots_data_handle_unittests.cc", + "updater_unittests.cc", ] - # This only includes snapshots_data_handle and not shorebird because - # shorebird fails to link due to a missing updater lib. deps = [ ":shorebird", ":shorebird_fixtures", ":snapshots_data_handle", + ":updater", "//flutter/runtime", "//flutter/runtime/shorebird:patch_cache", "//flutter/testing", diff --git a/engine/src/flutter/shell/common/shorebird/shorebird.cc b/engine/src/flutter/shell/common/shorebird/shorebird.cc index d040e07e0285d..71d336e90f8b0 100644 --- a/engine/src/flutter/shell/common/shorebird/shorebird.cc +++ b/engine/src/flutter/shell/common/shorebird/shorebird.cc @@ -19,13 +19,12 @@ #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" -#include "third_party/updater/library/include/updater.h" - // Namespaced to avoid Google style warnings. namespace flutter { @@ -80,7 +79,7 @@ class FileCallbacksImpl { static void Close(void* file); }; -FileCallbacks ShorebirdFileCallbacks() { +shorebird::FileCallbacks ShorebirdFileCallbacks() { return { .open = FileCallbacksImpl::Open, .read = FileCallbacksImpl::Read, @@ -137,33 +136,22 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, {shorebird_updater_dir_name}, fml::FilePermission::kReadWrite); - bool init_result; - // Using a block to make AppParameters lifetime explicit. - { - AppParameters app_parameters; - // 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; - } - - app_parameters.release_version = release_version.c_str(); - app_parameters.code_cache_dir = code_cache_dir.c_str(); - app_parameters.app_storage_dir = app_storage_dir.c_str(); + // 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; + } - // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c - std::vector c_paths{}; - c_paths.push_back(args.release_app_library_path.c_str()); - // Do not modify application_library_paths or c_strings will invalidate. + 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; - app_parameters.original_libapp_paths = c_paths.data(); - app_parameters.original_libapp_paths_size = c_paths.size(); - - // shorebird_init copies from app_parameters and shorebirdYaml. - init_result = shorebird_init(&app_parameters, ShorebirdFileCallbacks(), - args.shorebird_yaml.c_str()); - } + 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 @@ -171,11 +159,10 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, // https://github.com/shorebirdtech/shorebird/issues/950 FML_LOG(INFO) << "Checking for active patch"; - shorebird_validate_next_boot_patch(); - char* c_active_path = shorebird_next_boot_patch_path(); - if (c_active_path != NULL) { - patch_path = c_active_path; - shorebird_free_string(c_active_path); + 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."; @@ -189,9 +176,9 @@ bool ConfigureShorebird(const ShorebirdConfigArgs& args, return false; } - if (shorebird_should_auto_update()) { + if (shorebird::Updater::Instance().ShouldAutoUpdate()) { FML_LOG(INFO) << "Starting Shorebird update"; - shorebird_start_update_thread(); + shorebird::Updater::Instance().StartUpdateThread(); } else { FML_LOG(INFO) << "Shorebird auto_update disabled, not checking for updates."; @@ -226,31 +213,17 @@ void ConfigureShorebird(std::string code_cache_path, {shorebird_updater_dir_name}, fml::FilePermission::kReadWrite); - bool init_result; - // Using a block to make AppParameters lifetime explicit. - { - AppParameters app_parameters; - // Combine version and version_code into a single string. - // We could also pass these separately through to the updater if needed. - auto release_version = version + "+" + version_code; - app_parameters.release_version = release_version.c_str(); - app_parameters.code_cache_dir = code_cache_dir.c_str(); - app_parameters.app_storage_dir = app_storage_dir.c_str(); - - // https://stackoverflow.com/questions/26032039/convert-vectorstring-into-char-c - std::vector c_paths{}; - for (const auto& string : settings.application_library_paths) { - c_paths.push_back(string.c_str()); - } - // Do not modify application_library_paths or c_strings will invalidate. - - app_parameters.original_libapp_paths = c_paths.data(); - app_parameters.original_libapp_paths_size = c_paths.size(); + // 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; - // shorebird_init copies from app_parameters and shorebirdYaml. - init_result = shorebird_init(&app_parameters, ShorebirdFileCallbacks(), - shorebird_yaml.c_str()); - } + 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 @@ -262,11 +235,9 @@ void ConfigureShorebird(std::string code_cache_path, SetBaseSnapshot(settings); #endif - shorebird_validate_next_boot_patch(); - char* c_active_path = shorebird_next_boot_patch_path(); - if (c_active_path != NULL) { - std::string active_path = c_active_path; - shorebird_free_string(c_active_path); + 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 @@ -292,9 +263,9 @@ void ConfigureShorebird(std::string code_cache_path, return; } - if (shorebird_should_auto_update()) { + if (shorebird::Updater::Instance().ShouldAutoUpdate()) { FML_LOG(INFO) << "Starting Shorebird update"; - shorebird_start_update_thread(); + shorebird::Updater::Instance().StartUpdateThread(); } else { FML_LOG(INFO) << "Shorebird auto_update disabled, not checking for updates."; 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..84de941ec2d40 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater.cc @@ -0,0 +1,166 @@ +// 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_; + +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(); +} + +#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::ReportLaunchStart() { + shorebird_report_launch_start(); +} + +void RealUpdater::ReportLaunchSuccess() { + shorebird_report_launch_success(); +} + +void RealUpdater::ReportLaunchFailure() { + 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::ReportLaunchStart() { + launch_start_count_++; + call_log_.push_back("ReportLaunchStart"); +} + +void MockUpdater::ReportLaunchSuccess() { + launch_success_count_++; + call_log_.push_back("ReportLaunchSuccess"); +} + +void MockUpdater::ReportLaunchFailure() { + 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..f6fa5a9a2f6d9 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater.h @@ -0,0 +1,191 @@ +// 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 + +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) +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 + virtual void ReportLaunchStart() = 0; + virtual void ReportLaunchSuccess() = 0; + virtual void ReportLaunchFailure() = 0; + + // 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(); + + protected: + Updater() = default; + + private: + static std::unique_ptr instance_; + static std::mutex instance_mutex_; +}; + +/// 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 ReportLaunchStart() override {} + void ReportLaunchSuccess() override {} + void ReportLaunchFailure() 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 ReportLaunchStart() override; + void ReportLaunchSuccess() override; + void ReportLaunchFailure() 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 ReportLaunchStart() override; + void ReportLaunchSuccess() override; + void ReportLaunchFailure() 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..97fb6ef2129f2 --- /dev/null +++ b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc @@ -0,0 +1,127 @@ +// 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 + +#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 + auto mock = std::make_unique(); + mock_ = mock.get(); + Updater::SetInstanceForTesting(std::move(mock)); + } + + void TearDown() override { + mock_ = nullptr; + Updater::ResetInstanceForTesting(); + } + + MockUpdater* mock_ = nullptr; +}; + +TEST_F(UpdaterTest, MockUpdaterTracksLaunchStartCalls) { + EXPECT_EQ(mock_->launch_start_count(), 0); + + Updater::Instance().ReportLaunchStart(); + EXPECT_EQ(mock_->launch_start_count(), 1); + + Updater::Instance().ReportLaunchStart(); + EXPECT_EQ(mock_->launch_start_count(), 2); +} + +TEST_F(UpdaterTest, MockUpdaterTracksLaunchSuccessCalls) { + EXPECT_EQ(mock_->launch_success_count(), 0); + + Updater::Instance().ReportLaunchSuccess(); + EXPECT_EQ(mock_->launch_success_count(), 1); +} + +TEST_F(UpdaterTest, MockUpdaterTracksLaunchFailureCalls) { + EXPECT_EQ(mock_->launch_failure_count(), 0); + + 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()); +} + +// Test that demonstrates the std::once_flag pattern works correctly. +// This is the same pattern used in TryLoadFromPatch. +TEST_F(UpdaterTest, OncePerProcessPatternOnlyCallsOnce) { + static std::once_flag test_flag; + int call_count = 0; + + auto simulate_patch_load = [&]() { + std::call_once(test_flag, [&]() { + call_count++; + Updater::Instance().ReportLaunchStart(); + }); + }; + + // Simulate multiple engines loading patches + simulate_patch_load(); // Engine 1 + simulate_patch_load(); // Engine 2 + simulate_patch_load(); // Engine 3 + + EXPECT_EQ(call_count, 1); + EXPECT_EQ(mock_->launch_start_count(), 1); +} + +} // 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 7beb4ee4d8fb6..066e16ae09567 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -185,8 +185,6 @@ source_set("flutter_shell_native_src") { public_configs = [ "//flutter:config" ] - include_dirs = [ "//flutter/updater" ] - defines = [] libs = [ @@ -194,17 +192,6 @@ source_set("flutter_shell_native_src") { "EGL", "GLESv2", ] - 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 { - assert(false, "Unsupported target_cpu") - } } action("gen_android_build_config_java") { diff --git a/engine/src/flutter/shell/platform/android/flutter_main.cc b/engine/src/flutter/shell/platform/android/flutter_main.cc index d881ca39efd3f..45e369f5b3a9d 100644 --- a/engine/src/flutter/shell/platform/android/flutter_main.cc +++ b/engine/src/flutter/shell/platform/android/flutter_main.cc @@ -30,8 +30,6 @@ #include "impeller/toolkit/android/proc_table.h" #include "txt/platform.h" -#include "third_party/updater/library/include/updater.h" - namespace flutter { constexpr int kMinimumAndroidApiLevelForImpeller = 29; diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index fd167854107b1..777b6ae4a64bb 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -75,14 +75,6 @@ source_set("flutter_framework_source") { "//build/config/ios:ios_application_extension", ] - 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 { - assert(false, "Unsupported target_cpu") - } - sources = [ "framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterAppDelegate_Internal.h", From 1102488790c5aaedda2e21d5f666792f09f76368 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 23 Jan 2026 17:40:51 -0800 Subject: [PATCH 100/105] chore: roll engine to 50b8af000ba26227acfba511ab40d9199c102625 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 418e37e7e44ae..ddc075f350955 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9ec97995930ec55f111a703f2ad9a3631ca7aa82 \ No newline at end of file +50b8af000ba26227acfba511ab40d9199c102625 \ No newline at end of file From 104f3eb18abaeb8e3551ec7d6ecedaac525f3d02 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Fri, 30 Jan 2026 18:41:39 -0800 Subject: [PATCH 101/105] fix: start/success reporting (#103) Previously we stopped reporting start on android by accident. This fixes that. I also removed the once-per-process guard since it's not necessary. This should be correctly reporting once-per-shell and let the rust code only handle the first of the calls. Fixes https://github.com/shorebirdtech/shorebird/issues/3488 --- engine/src/flutter/runtime/dart_snapshot.cc | 6 +++ .../flutter/runtime/shorebird/patch_cache.cc | 15 ++----- .../flutter/shell/common/shell_unittests.cc | 42 +++++++++-------- .../common/shorebird/updater_unittests.cc | 45 ++++++++++--------- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/engine/src/flutter/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index b822d98604712..dc487590f65a7 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -17,6 +17,7 @@ #if SHOREBIRD_USE_INTERPRETER #include "flutter/runtime/shorebird/patch_cache.h" // nogncheck #endif +#include "flutter/shell/common/shorebird/updater.h" // nogncheck namespace flutter { @@ -151,6 +152,11 @@ static std::shared_ptr ResolveIsolateData( true // dontneed_safe ); #else // DART_SNAPSHOT_STATIC_LINK + // Report launch start to pair with ReportLaunchSuccess/ReportLaunchFailure + // in Shell::Shell. Called once per engine, matching the per-engine success/ + // failure calls. The Rust updater no-ops when no patch is booting. + FML_LOG(INFO) << "Reporting launch start for patch"; + shorebird::Updater::Instance().ReportLaunchStart(); #if SHOREBIRD_USE_INTERPRETER // Try loading from a Shorebird patch first. if (auto mapping = TryLoadFromPatch(settings.application_library_paths, diff --git a/engine/src/flutter/runtime/shorebird/patch_cache.cc b/engine/src/flutter/runtime/shorebird/patch_cache.cc index b835d01b98639..8c5cc3a83f182 100644 --- a/engine/src/flutter/runtime/shorebird/patch_cache.cc +++ b/engine/src/flutter/runtime/shorebird/patch_cache.cc @@ -9,7 +9,6 @@ #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "flutter/runtime/shorebird/patch_mapping.h" -#include "flutter/shell/common/shorebird/updater.h" #include "third_party/dart/runtime/include/dart_api.h" namespace flutter { @@ -152,18 +151,10 @@ std::shared_ptr TryLoadFromPatch( FML_LOG(INFO) << "Loading symbol from patch: " << symbol_name; - // Report launch_start when we're actually about to use a patch. - // This is called at exactly the right time - right before the patched - // snapshot is loaded. We use std::once_flag to ensure it's only called - // once per process, and only for the first symbol (isolate data). - // This fixes the FlutterEngineGroup issue where report_launch_start was - // called too early (in ConfigureShorebird) before any patch was used. - static std::once_flag launch_start_flag; + // ReportLaunchStart is now called from ResolveIsolateData in + // dart_snapshot.cc, which runs before TryLoadFromPatch on all platforms. + if (symbol == kIsolateDataSymbol) { - std::call_once(launch_start_flag, []() { - FML_LOG(INFO) << "Reporting launch start for patch"; - shorebird::Updater::Instance().ReportLaunchStart(); - }); return PatchMapping::CreateIsolateData(cache_entry); } else { FML_CHECK(symbol == kIsolateInstructionsSymbol); diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index 6bb7907b3936e..07a3a44f2430f 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -5109,60 +5109,58 @@ TEST_F(ShellTest, ShoulDiscardLayerTreeIfFrameIsSizedIncorrectly) { DestroyShell(std::move(shell), task_runners); } -// Test that Shell creation triggers the Shorebird Updater's ReportLaunchSuccess -// call. This is important for the crash recovery mechanism to work correctly. -TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessOnShellCreation) { - // Install a mock updater before creating the shell +// Test the full boot flow: ReportLaunchStart is called from +// ResolveIsolateData, then ReportLaunchSuccess from the Shell constructor. +// Each shell gets a paired Start+Success. +TEST_F(ShellTest, ShorebirdBootFlowCallsLaunchStartThenSuccess) { auto mock = std::make_unique(); auto* mock_ptr = mock.get(); shorebird::Updater::SetInstanceForTesting(std::move(mock)); - EXPECT_EQ(mock_ptr->launch_success_count(), 0); - EXPECT_EQ(mock_ptr->launch_failure_count(), 0); - auto settings = CreateSettingsForFixture(); auto task_runners = GetTaskRunnersForFixture(); auto shell = CreateShell(settings, task_runners); ASSERT_TRUE(shell); - // Shell constructor should have called ReportLaunchSuccess - EXPECT_EQ(mock_ptr->launch_success_count(), 1); - EXPECT_EQ(mock_ptr->launch_failure_count(), 0); - - // Verify the call was logged const auto& log = mock_ptr->call_log(); - EXPECT_TRUE(std::find(log.begin(), log.end(), "ReportLaunchSuccess") != - log.end()); + ASSERT_EQ(log.size(), 2u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); DestroyShell(std::move(shell), task_runners); - - // Clean up - reset the updater instance shorebird::Updater::ResetInstanceForTesting(); } -// Test that creating multiple shells only calls ReportLaunchSuccess for each -// shell. This verifies that each Shell reports its own launch status. +// Test that each shell gets a paired ReportLaunchStart + ReportLaunchSuccess. TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessForMultipleShells) { auto mock = std::make_unique(); auto* mock_ptr = mock.get(); shorebird::Updater::SetInstanceForTesting(std::move(mock)); - EXPECT_EQ(mock_ptr->launch_success_count(), 0); - auto settings = CreateSettingsForFixture(); - // Create first shell + // 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 + // Create second shell — also gets Start + Success auto task_runners2 = GetTaskRunnersForFixture(); auto shell2 = CreateShell(settings, task_runners2); ASSERT_TRUE(shell2); + EXPECT_EQ(mock_ptr->launch_start_count(), 2); EXPECT_EQ(mock_ptr->launch_success_count(), 2); + // Full call log: Start+Success per shell + const auto& log = mock_ptr->call_log(); + ASSERT_EQ(log.size(), 4u); + EXPECT_EQ(log[0], "ReportLaunchStart"); + EXPECT_EQ(log[1], "ReportLaunchSuccess"); + EXPECT_EQ(log[2], "ReportLaunchStart"); + EXPECT_EQ(log[3], "ReportLaunchSuccess"); + DestroyShell(std::move(shell1), task_runners1); DestroyShell(std::move(shell2), task_runners2); diff --git a/engine/src/flutter/shell/common/shorebird/updater_unittests.cc b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc index 97fb6ef2129f2..569673a9e5b1c 100644 --- a/engine/src/flutter/shell/common/shorebird/updater_unittests.cc +++ b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc @@ -4,8 +4,6 @@ #include "flutter/shell/common/shorebird/updater.h" -#include - #include "gtest/gtest.h" namespace flutter { @@ -100,26 +98,31 @@ TEST_F(UpdaterTest, MockUpdaterResetClearsState) { EXPECT_FALSE(mock_->ShouldAutoUpdate()); } -// Test that demonstrates the std::once_flag pattern works correctly. -// This is the same pattern used in TryLoadFromPatch. -TEST_F(UpdaterTest, OncePerProcessPatternOnlyCallsOnce) { - static std::once_flag test_flag; - int call_count = 0; - - auto simulate_patch_load = [&]() { - std::call_once(test_flag, [&]() { - call_count++; - Updater::Instance().ReportLaunchStart(); - }); - }; - - // Simulate multiple engines loading patches - simulate_patch_load(); // Engine 1 - simulate_patch_load(); // Engine 2 - simulate_patch_load(); // Engine 3 - - EXPECT_EQ(call_count, 1); +// ReportLaunchStart and ReportLaunchSuccess are always paired per shell. +// The Rust updater no-ops both when no patch is booting. +TEST_F(UpdaterTest, LaunchStartAndSuccessAreAlwaysPaired) { + 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 on failed boots. +TEST_F(UpdaterTest, LaunchStartAndFailureAreAlwaysPaired) { + 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"); } } // namespace testing From 3e4a0f12f17d37e3e0325f880225c09a477008b1 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 2 Feb 2026 14:18:22 -0800 Subject: [PATCH 102/105] chore: engine roll to 104f3eb18a (#104) Co-authored-by: Brandon DeRosier --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ddc075f350955..888d159660336 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -50b8af000ba26227acfba511ab40d9199c102625 \ No newline at end of file +104f3eb18abaeb8e3551ec7d6ecedaac525f3d02 \ No newline at end of file From e9ab53b190d5af1895e140e2eff0051de76dc9ff Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 2 Feb 2026 16:17:02 -0800 Subject: [PATCH 103/105] fix: only call shorebird_report_start once (#105) As part of our previous fix for FlutterEngineGroup, we introduced a new bug whereby report_launch_start could be called more than once in a multi-engine scenerio. That would cause confusion about what the current boot patch is, since the current patch is updated as part of report_launch_start. report_launch_start should only be called once per processs, which this change fixes. We still need more end-to-end testing at this layer to prevent bugs like this from sneaking in. --- engine/src/flutter/runtime/dart_snapshot.cc | 9 +-- engine/src/flutter/shell/common/shell.cc | 7 +- .../flutter/shell/common/shell_unittests.cc | 26 ++++--- .../flutter/shell/common/shorebird/updater.cc | 48 +++++++++++-- .../flutter/shell/common/shorebird/updater.h | 65 +++++++++++++---- .../common/shorebird/updater_unittests.cc | 71 ++++++++++++++++--- 6 files changed, 183 insertions(+), 43 deletions(-) diff --git a/engine/src/flutter/runtime/dart_snapshot.cc b/engine/src/flutter/runtime/dart_snapshot.cc index dc487590f65a7..fc70f63a346f2 100644 --- a/engine/src/flutter/runtime/dart_snapshot.cc +++ b/engine/src/flutter/runtime/dart_snapshot.cc @@ -152,10 +152,11 @@ static std::shared_ptr ResolveIsolateData( true // dontneed_safe ); #else // DART_SNAPSHOT_STATIC_LINK - // Report launch start to pair with ReportLaunchSuccess/ReportLaunchFailure - // in Shell::Shell. Called once per engine, matching the per-engine success/ - // failure calls. The Rust updater no-ops when no patch is booting. - FML_LOG(INFO) << "Reporting launch start for patch"; + // 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. diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index cb523c5985d44..57d751b19f578 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -523,7 +523,12 @@ Shell::Shell(DartVMRef vm, is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)), weak_factory_gpu_(nullptr), weak_factory_(this) { - // Report launch status to Shorebird updater for crash recovery tracking. + // 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(); diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index 07a3a44f2430f..07b9310166b5d 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -5111,11 +5111,12 @@ TEST_F(ShellTest, ShoulDiscardLayerTreeIfFrameIsSizedIncorrectly) { // Test the full boot flow: ReportLaunchStart is called from // ResolveIsolateData, then ReportLaunchSuccess from the Shell constructor. -// Each shell gets a paired Start+Success. +// 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(); @@ -5128,14 +5129,20 @@ TEST_F(ShellTest, ShorebirdBootFlowCallsLaunchStartThenSuccess) { EXPECT_EQ(log[1], "ReportLaunchSuccess"); DestroyShell(std::move(shell), task_runners); + shorebird::Updater::ResetLaunchStateForTesting(); shorebird::Updater::ResetInstanceForTesting(); } -// Test that each shell gets a paired ReportLaunchStart + ReportLaunchSuccess. -TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessForMultipleShells) { +// 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(); @@ -5146,24 +5153,23 @@ TEST_F(ShellTest, ShorebirdUpdaterReportLaunchSuccessForMultipleShells) { EXPECT_EQ(mock_ptr->launch_start_count(), 1); EXPECT_EQ(mock_ptr->launch_success_count(), 1); - // Create second shell — also gets Start + Success + // 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(), 2); - EXPECT_EQ(mock_ptr->launch_success_count(), 2); + EXPECT_EQ(mock_ptr->launch_start_count(), 1); + EXPECT_EQ(mock_ptr->launch_success_count(), 1); - // Full call log: Start+Success per shell + // Only one Start+Success pair in the call log. const auto& log = mock_ptr->call_log(); - ASSERT_EQ(log.size(), 4u); + ASSERT_EQ(log.size(), 2u); EXPECT_EQ(log[0], "ReportLaunchStart"); EXPECT_EQ(log[1], "ReportLaunchSuccess"); - EXPECT_EQ(log[2], "ReportLaunchStart"); - EXPECT_EQ(log[3], "ReportLaunchSuccess"); DestroyShell(std::move(shell1), task_runners1); DestroyShell(std::move(shell2), task_runners2); + shorebird::Updater::ResetLaunchStateForTesting(); shorebird::Updater::ResetInstanceForTesting(); } diff --git a/engine/src/flutter/shell/common/shorebird/updater.cc b/engine/src/flutter/shell/common/shorebird/updater.cc index 84de941ec2d40..63d993613c3f9 100644 --- a/engine/src/flutter/shell/common/shorebird/updater.cc +++ b/engine/src/flutter/shell/common/shorebird/updater.cc @@ -16,6 +16,8 @@ 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_); @@ -39,6 +41,40 @@ void Updater::ResetInstanceForTesting() { 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 @@ -81,15 +117,15 @@ std::string RealUpdater::NextBootPatchPath() { return path; } -void RealUpdater::ReportLaunchStart() { +void RealUpdater::DoReportLaunchStart() { shorebird_report_launch_start(); } -void RealUpdater::ReportLaunchSuccess() { +void RealUpdater::DoReportLaunchSuccess() { shorebird_report_launch_success(); } -void RealUpdater::ReportLaunchFailure() { +void RealUpdater::DoReportLaunchFailure() { shorebird_report_launch_failure(); } @@ -122,17 +158,17 @@ std::string MockUpdater::NextBootPatchPath() { return next_boot_patch_path_; } -void MockUpdater::ReportLaunchStart() { +void MockUpdater::DoReportLaunchStart() { launch_start_count_++; call_log_.push_back("ReportLaunchStart"); } -void MockUpdater::ReportLaunchSuccess() { +void MockUpdater::DoReportLaunchSuccess() { launch_success_count_++; call_log_.push_back("ReportLaunchSuccess"); } -void MockUpdater::ReportLaunchFailure() { +void MockUpdater::DoReportLaunchFailure() { launch_failure_count_++; call_log_.push_back("ReportLaunchFailure"); } diff --git a/engine/src/flutter/shell/common/shorebird/updater.h b/engine/src/flutter/shell/common/shorebird/updater.h index f6fa5a9a2f6d9..aeb2d1f2d90cc 100644 --- a/engine/src/flutter/shell/common/shorebird/updater.h +++ b/engine/src/flutter/shell/common/shorebird/updater.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_SHELL_COMMON_SHOREBIRD_UPDATER_H_ #define FLUTTER_SHELL_COMMON_SHOREBIRD_UPDATER_H_ +#include #include #include #include @@ -52,6 +53,29 @@ struct AppConfig { /// 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; @@ -69,10 +93,12 @@ class Updater { /// @return Path to patch, or empty string if no patch available virtual std::string NextBootPatchPath() = 0; - // Boot lifecycle methods - virtual void ReportLaunchStart() = 0; - virtual void ReportLaunchSuccess() = 0; - virtual void ReportLaunchFailure() = 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; @@ -85,12 +111,25 @@ class Updater { 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. @@ -103,9 +142,9 @@ class NoOpUpdater : public Updater { bool Init(const AppConfig& config) override { return true; } void ValidateNextBootPatch() override {} std::string NextBootPatchPath() override { return ""; } - void ReportLaunchStart() override {} - void ReportLaunchSuccess() override {} - void ReportLaunchFailure() override {} + void DoReportLaunchStart() override {} + void DoReportLaunchSuccess() override {} + void DoReportLaunchFailure() override {} bool ShouldAutoUpdate() override { return false; } void StartUpdateThread() override {} }; @@ -121,9 +160,9 @@ class RealUpdater : public Updater { bool Init(const AppConfig& config) override; void ValidateNextBootPatch() override; std::string NextBootPatchPath() override; - void ReportLaunchStart() override; - void ReportLaunchSuccess() override; - void ReportLaunchFailure() override; + void DoReportLaunchStart() override; + void DoReportLaunchSuccess() override; + void DoReportLaunchFailure() override; bool ShouldAutoUpdate() override; void StartUpdateThread() override; }; @@ -139,9 +178,9 @@ class MockUpdater : public Updater { bool Init(const AppConfig& config) override; void ValidateNextBootPatch() override; std::string NextBootPatchPath() override; - void ReportLaunchStart() override; - void ReportLaunchSuccess() override; - void ReportLaunchFailure() override; + void DoReportLaunchStart() override; + void DoReportLaunchSuccess() override; + void DoReportLaunchFailure() override; bool ShouldAutoUpdate() override; void StartUpdateThread() override; diff --git a/engine/src/flutter/shell/common/shorebird/updater_unittests.cc b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc index 569673a9e5b1c..def93050e885d 100644 --- a/engine/src/flutter/shell/common/shorebird/updater_unittests.cc +++ b/engine/src/flutter/shell/common/shorebird/updater_unittests.cc @@ -13,42 +13,56 @@ namespace testing { class UpdaterTest : public ::testing::Test { protected: void SetUp() override { - // Install a mock for each test + // 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; }; -TEST_F(UpdaterTest, MockUpdaterTracksLaunchStartCalls) { +// 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(), 2); + EXPECT_EQ(mock_->launch_start_count(), 1); } -TEST_F(UpdaterTest, MockUpdaterTracksLaunchSuccessCalls) { +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, MockUpdaterTracksLaunchFailureCalls) { +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) { @@ -98,9 +112,9 @@ TEST_F(UpdaterTest, MockUpdaterResetClearsState) { EXPECT_FALSE(mock_->ShouldAutoUpdate()); } -// ReportLaunchStart and ReportLaunchSuccess are always paired per shell. +// ReportLaunchStart and ReportLaunchSuccess are paired once per process. // The Rust updater no-ops both when no patch is booting. -TEST_F(UpdaterTest, LaunchStartAndSuccessAreAlwaysPaired) { +TEST_F(UpdaterTest, LaunchStartAndSuccessArePairedOncePerProcess) { Updater::Instance().ReportLaunchStart(); Updater::Instance().ReportLaunchSuccess(); @@ -112,8 +126,8 @@ TEST_F(UpdaterTest, LaunchStartAndSuccessAreAlwaysPaired) { EXPECT_EQ(log[1], "ReportLaunchSuccess"); } -// ReportLaunchStart and ReportLaunchFailure are paired on failed boots. -TEST_F(UpdaterTest, LaunchStartAndFailureAreAlwaysPaired) { +// ReportLaunchStart and ReportLaunchFailure are paired once per process. +TEST_F(UpdaterTest, LaunchStartAndFailureArePairedOncePerProcess) { Updater::Instance().ReportLaunchStart(); Updater::Instance().ReportLaunchFailure(); @@ -125,6 +139,45 @@ TEST_F(UpdaterTest, LaunchStartAndFailureAreAlwaysPaired) { 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 From 8f6ff054cf48a1b3e07834eec93a129b539435ce Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 2 Feb 2026 16:56:02 -0800 Subject: [PATCH 104/105] feat: show logs when running shorebird_tests (#106) --- .../shorebird_tests/test/shorebird_tests.dart | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/shorebird_tests/test/shorebird_tests.dart b/packages/shorebird_tests/test/shorebird_tests.dart index 4bead2de4503e..e332d8714d34a 100644 --- a/packages/shorebird_tests/test/shorebird_tests.dart +++ b/packages/shorebird_tests/test/shorebird_tests.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:archive/archive_io.dart'; @@ -23,12 +24,19 @@ File get _flutterBinaryFile => File( ); /// Runs a flutter command using the correct binary ([_flutterBinaryFile]) with the given arguments. +/// +/// Streams stdout and stderr to the test output in real time so that +/// CI logs show progress even if the process hangs or times out. Future _runFlutterCommand( List arguments, { required Directory workingDirectory, Map? environment, -}) { - return Process.run( +}) 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, @@ -37,6 +45,40 @@ Future _runFlutterCommand( if (environment != null) ...environment, }, ); + + final StringBuffer stdoutBuffer = StringBuffer(); + final StringBuffer stderrBuffer = StringBuffer(); + + process.stdout.transform(utf8.decoder).listen((String data) { + stdoutBuffer.write(data); + // Print each line with a prefix so it's easy to identify in CI logs. + 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); + 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)'); + + return ProcessResult( + process.pid, + exitCode, + stdoutBuffer.toString(), + stderrBuffer.toString(), + ); } Future _createFlutterProject(Directory projectDirectory) async { From 6c462e781297ec30e9b886f304912cafd1a4ab5a Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 2 Feb 2026 16:56:41 -0800 Subject: [PATCH 105/105] feat: add verbose logging to shorebird_tests for CI debugging Stream subprocess output in real time when VERBOSE is set, and dump stdout/stderr on failure. This helps diagnose flaky timeout failures in CI where buffered output is lost when the test times out. --- .github/workflows/shorebird_ci.yml | 3 ++ .../shorebird_tests/test/shorebird_tests.dart | 31 +++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/shorebird_ci.yml b/.github/workflows/shorebird_ci.yml index 9597d6a599344..a1a81b5ef5d66 100644 --- a/.github/workflows/shorebird_ci.yml +++ b/.github/workflows/shorebird_ci.yml @@ -50,3 +50,6 @@ jobs: 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/packages/shorebird_tests/test/shorebird_tests.dart b/packages/shorebird_tests/test/shorebird_tests.dart index e332d8714d34a..6c08685ad29ef 100644 --- a/packages/shorebird_tests/test/shorebird_tests.dart +++ b/packages/shorebird_tests/test/shorebird_tests.dart @@ -23,10 +23,16 @@ File get _flutterBinaryFile => File( ), ); +/// 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 so that -/// CI logs show progress even if the process hangs or times out. +/// 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, @@ -51,19 +57,22 @@ Future _runFlutterCommand( process.stdout.transform(utf8.decoder).listen((String data) { stdoutBuffer.write(data); - // Print each line with a prefix so it's easy to identify in CI logs. - for (final String line in data.split('\n')) { - if (line.isNotEmpty) { - print(' [$command] $line'); + 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); - for (final String line in data.split('\n')) { - if (line.isNotEmpty) { - print(' [$command] (stderr) $line'); + if (_verbose) { + for (final String line in data.split('\n')) { + if (line.isNotEmpty) { + print(' [$command] (stderr) $line'); + } } } }); @@ -72,6 +81,10 @@ Future _runFlutterCommand( 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,