[flutter_releases] Flutter beta 2.8.0-3.3.pre Framework Cherrypicks (#94490)

* make CIPD url customizable using FLUTTER_STORAGE_BASE_URL (#94137)

* 'Update Engine revision to 06a7363b0cfd4092fe06eb80f829b5fbc94fd32a for beta release 2.8.0-3.3.pre'

* Update plugin lint test for federated url_launcher plugin (#94374)

Co-authored-by: Yegor <yjbanov@google.com>
Co-authored-by: Jenn Magder <magder@google.com>
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index c4e64cc..fdd5b78 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-bcc2b7f12cada3d1359e353c416568b4c3f6df69
+06a7363b0cfd4092fe06eb80f829b5fbc94fd32a
diff --git a/dev/devicelab/bin/tasks/plugin_lint_mac.dart b/dev/devicelab/bin/tasks/plugin_lint_mac.dart
index b92f422..052a7d4 100644
--- a/dev/devicelab/bin/tasks/plugin_lint_mac.dart
+++ b/dev/devicelab/bin/tasks/plugin_lint_mac.dart
@@ -399,7 +399,7 @@
 
       final File podfileLockFile = File(path.join(swiftAppPath, 'ios', 'Podfile.lock'));
       final String podfileLockOutput = podfileLockFile.readAsStringSync();
-      if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher/ios"')
+      if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher_ios/ios"')
         || !podfileLockOutput.contains(':path: Flutter')
           // test_plugin_objc no longer supports iOS, shouldn't be present.
         || podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_objc/ios"')
@@ -417,7 +417,7 @@
 
       checkDirectoryExists(path.join(
         pluginSymlinks,
-        'url_launcher',
+        'url_launcher_ios',
         'ios',
       ));
 
@@ -447,7 +447,7 @@
 
   final File podfileLockFile = File(path.join(appPath, 'ios', 'Podfile.lock'));
   final String podfileLockOutput = podfileLockFile.readAsStringSync();
-  if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher/ios"')
+  if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher_ios/ios"')
     || !podfileLockOutput.contains(':path: Flutter')
     || !podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_objc/ios"')
     || !podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_swift/ios"')
@@ -479,7 +479,7 @@
 
   checkDirectoryExists(path.join(
     pluginSymlinks,
-    'url_launcher',
+    'url_launcher_ios',
     'ios',
   ));
 
@@ -516,7 +516,7 @@
   if (!podfileLockOutput.contains(':path: Flutter/ephemeral\n')
       || !podfileLockOutput.contains(':path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos')
       || !podfileLockOutput.contains(':path: Flutter/ephemeral/.symlinks/plugins/test_plugin_swift/macos')
-      || podfileLockOutput.contains('url_launcher/')) {
+      || podfileLockOutput.contains('url_launcher_ios/')) {
     print(podfileLockOutput);
     throw TaskResult.failure('macOS Podfile.lock does not contain expected pods');
   }
@@ -546,7 +546,7 @@
 
   checkDirectoryNotExists(path.join(
     pluginSymlinks,
-    'url_launcher',
+    'url_launcher_ios',
   ));
 
   checkDirectoryExists(path.join(
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 254c68e..7870c78 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -412,6 +412,29 @@
     return overrideUrl;
   }
 
+  String get cipdBaseUrl {
+    final String? overrideUrl = _platform.environment['FLUTTER_STORAGE_BASE_URL'];
+    if (overrideUrl == null) {
+      return 'https://chrome-infra-packages.appspot.com/dl';
+    }
+
+    final Uri original;
+    try {
+      original = Uri.parse(overrideUrl);
+    } on FormatException catch (err) {
+      throwToolExit('"FLUTTER_STORAGE_BASE_URL" contains an invalid URI:\n$err');
+    }
+
+    final String cipdOverride = original.replace(
+      pathSegments: <String>[
+        ...original.pathSegments,
+        'flutter_infra_release',
+        'cipd',
+      ],
+    ).toString();
+    return cipdOverride;
+  }
+
   bool _hasWarnedAboutStorageOverride = false;
 
   void _maybeWarnAboutStorageOverride(String overrideUrl) {
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index 9e29d5a..ae479b4 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -198,7 +198,7 @@
     }
 
     final String canvasKitVersion = cache.getVersionFor('canvaskit')!;
-    final String canvasKitUrl = '$_cipdBaseUrl/flutter/web/canvaskit_bundle/+/$canvasKitVersion';
+    final String canvasKitUrl = '${cache.cipdBaseUrl}/flutter/web/canvaskit_bundle/+/$canvasKitVersion';
     return artifactUpdater.downloadZipArchive(
       'Downloading CanvasKit...',
       Uri.parse(canvasKitUrl),
@@ -575,8 +575,6 @@
   }
 }
 
-const String _cipdBaseUrl = 'https://chrome-infra-packages.appspot.com/dl';
-
 /// Common functionality for pulling Fuchsia SDKs.
 abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
   _FuchsiaSDKArtifacts(Cache cache, String platform) :
@@ -593,7 +591,7 @@
   Directory get location => cache.getArtifactDirectory('fuchsia');
 
   Future<void> _doUpdate(ArtifactUpdater artifactUpdater) {
-    final String url = '$_cipdBaseUrl/$_path/+/$version';
+    final String url = '${cache.cipdBaseUrl}/$_path/+/$version';
     return artifactUpdater.downloadZipArchive('Downloading package fuchsia SDK...',
                                Uri.parse(url), location);
   }
@@ -627,7 +625,7 @@
     if (!_platform.isLinux && !_platform.isMacOS) {
       return;
     }
-    final String url = '$_cipdBaseUrl/flutter/fuchsia/+/git_revision:$version';
+    final String url = '${cache.cipdBaseUrl}/flutter/fuchsia/+/git_revision:$version';
     await artifactUpdater.downloadZipArchive('Downloading package flutter runner...', Uri.parse(url), location);
   }
 }
@@ -644,11 +642,13 @@
 
 /// Resolves the CIPD archive URL for a given package and version.
 class CipdArchiveResolver extends VersionedPackageResolver {
-  const CipdArchiveResolver();
+  const CipdArchiveResolver(this.cache);
+
+  final Cache cache;
 
   @override
   String resolveUrl(String packageName, String version) {
-    return '$_cipdBaseUrl/flutter/$packageName/+/git_revision:$version';
+    return '${cache.cipdBaseUrl}/flutter/$packageName/+/git_revision:$version';
   }
 }
 
@@ -656,9 +656,10 @@
 class FlutterRunnerDebugSymbols extends CachedArtifact {
   FlutterRunnerDebugSymbols(Cache cache, {
     required Platform platform,
-    this.packageResolver = const CipdArchiveResolver(),
+    VersionedPackageResolver? packageResolver,
   }) : _platform = platform,
-      super('flutter_runner_debug_symbols', cache, DevelopmentArtifact.flutterRunner);
+       packageResolver = packageResolver ?? CipdArchiveResolver(cache),
+       super('flutter_runner_debug_symbols', cache, DevelopmentArtifact.flutterRunner);
 
   final VersionedPackageResolver packageResolver;
   final Platform _platform;
diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart
index 24b3302..22ed53b 100644
--- a/packages/flutter_tools/test/general.shard/cache_test.dart
+++ b/packages/flutter_tools/test/general.shard/cache_test.dart
@@ -730,14 +730,18 @@
 
   testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async {
     final MemoryFileSystem fileSystem = MemoryFileSystem.test();
-    final File canvasKitVersionFile = fileSystem.currentDirectory
+    final Directory internalDir = fileSystem.currentDirectory
       .childDirectory('cache')
       .childDirectory('bin')
-      .childDirectory('internal')
-      .childFile('canvaskit.version');
+      .childDirectory('internal');
+    final File canvasKitVersionFile = internalDir.childFile('canvaskit.version');
     canvasKitVersionFile.createSync(recursive: true);
     canvasKitVersionFile.writeAsStringSync('abcdefg');
 
+    final File engineVersionFile = internalDir.childFile('engine.version');
+    engineVersionFile.createSync(recursive: true);
+    engineVersionFile.writeAsStringSync('hijklmnop');
+
     final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem);
     final Directory webCacheDirectory = cache.getWebSdkDirectory();
     final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
@@ -763,7 +767,7 @@
     ]);
 
     expect(downloads, <String>[
-      'https://storage.googleapis.com/flutter_infra_release/flutter/null/flutter-web-sdk-linux-x64.zip',
+      'https://storage.googleapis.com/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk-linux-x64.zip',
       'https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle/+/abcdefg',
     ]);
 
@@ -776,6 +780,51 @@
     expect(webCacheDirectory.childFile('bar'), isNot(exists));
   });
 
+  testWithoutContext('FlutterWebSdk CanvasKit URL can be overridden via FLUTTER_STORAGE_BASE_URL', () async {
+    final MemoryFileSystem fileSystem = MemoryFileSystem.test();
+    final Directory internalDir = fileSystem.currentDirectory
+      .childDirectory('cache')
+      .childDirectory('bin')
+      .childDirectory('internal');
+    final File canvasKitVersionFile = internalDir.childFile('canvaskit.version');
+    canvasKitVersionFile.createSync(recursive: true);
+    canvasKitVersionFile.writeAsStringSync('abcdefg');
+
+    final File engineVersionFile = internalDir.childFile('engine.version');
+    engineVersionFile.createSync(recursive: true);
+    engineVersionFile.writeAsStringSync('hijklmnop');
+
+    final Cache cache = Cache.test(
+      processManager: FakeProcessManager.any(),
+      fileSystem: fileSystem,
+      platform: FakePlatform(
+        environment: <String, String>{
+          'FLUTTER_STORAGE_BASE_URL': 'https://flutter.storage.com/override'
+        },
+      ),
+    );
+    final Directory webCacheDirectory = cache.getWebSdkDirectory();
+    final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
+    final FlutterWebSdk webSdk = FlutterWebSdk(cache, platform: FakePlatform());
+
+    final List<String> downloads = <String>[];
+    final List<String> locations = <String>[];
+    artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) {
+      downloads.add(uri.toString());
+      locations.add(location.path);
+      location.createSync(recursive: true);
+      location.childFile('foo').createSync();
+    };
+    webCacheDirectory.childFile('bar').createSync(recursive: true);
+
+    await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils());
+
+    expect(downloads, <String>[
+      'https://flutter.storage.com/override/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk-linux-x64.zip',
+      'https://flutter.storage.com/override/flutter_infra_release/cipd/flutter/web/canvaskit_bundle/+/abcdefg'
+    ]);
+  });
+
   testWithoutContext('FlutterWebSdk uses tryToDelete to handle directory edge cases', () async {
     final FileExceptionHandler handler = FileExceptionHandler();
     final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle);