v1.12.13+hotfix.3 cherry-picks (#46204)

* flutter/engine@ac93919 v1.12.13+hotfix.3 cherry-picks
  * flutter/engine@73da385 Disable a11y on detach
* d88345e only run codecov on master
* 6d848eb Name the docker_builer shard
* e98acc7 [flutter_tool] Print version info on a no-op upgrade
* 8eb6a92 Always compile with isysroot on iOS to point to SDK root
* fb69a39 Add bitcode and architectures to App.framework build ios framework command
diff --git a/.cirrus.yml b/.cirrus.yml
index 51a58da..415a388 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,4 +1,5 @@
 # CIRRUS CONFIGURATION FILE
+# https://cirrus-ci.org/guide/writing-tasks/
 
 use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true'
 
@@ -135,7 +136,7 @@
         - dart --enable-asserts ./dev/bots/test.dart
 
     - name: tool_coverage-linux # linux-only
-      only_if: "$CIRRUS_PR == ''"
+      only_if: "$CIRRUS_BRANCH == 'master'"
       environment:
         # As of October 2019, the tool_coverage-linux shard needed at least 12G of RAM to run without
         # getting OOM-killed, and even 8 CPUs took 25 minutes.
@@ -578,9 +579,10 @@
 
 docker_builder:
   # Only build a new docker image when we tag a release (for dev, beta, or
-  # release.) Note: tagging a commit and pushing to a release branch are
+  # stable). Note: tagging a commit and pushing to a release branch are
   # different cirrus triggers. See a tag CI run at e.g.
   # https://cirrus-ci.com/github/flutter/flutter/v1.2.3
+  name: docker_build
   only_if: $CIRRUS_TAG != ''
   environment:
     GCLOUD_CREDENTIALS: ENCRYPTED[f7c098d4dd7f5ee1bfee0bb7e944cce72efbe10e97ad6440ae72de4de6a1c24d23f421a2619c668e94377fb64b0bb3e6]
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index 1842d08..e3574c1 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-6955b06cedb2425f4363f10642c9b0e63e496af0
+ac9391978e7c0693b75a82c219e059b6ffee35c4
diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
index 594c2a3..5eef7f5 100644
--- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
@@ -79,18 +79,33 @@
         'App',
       ));
 
-      final String aotSymbols = await dylibSymbols(path.join(
+      final String appFrameworkPath = path.join(
         outputPath,
         'Debug',
         'App.framework',
         'App',
-      ));
+      );
+      final String aotSymbols = await dylibSymbols(appFrameworkPath);
 
       if (aotSymbols.contains('architecture') ||
           aotSymbols.contains('_kDartVmSnapshot')) {
         throw TaskResult.failure('Debug App.framework contains AOT');
       }
 
+      final String debugAppArchs = await fileType(appFrameworkPath);
+
+      if (!debugAppArchs.contains('armv7')) {
+        throw TaskResult.failure('Debug App.framework armv7 architecture missing');
+      }
+
+      if (!debugAppArchs.contains('arm64')) {
+        throw TaskResult.failure('Debug App.framework arm64 architecture missing');
+      }
+
+      if (!debugAppArchs.contains('x86_64')) {
+        throw TaskResult.failure('Debug App.framework x86_64 architecture missing');
+      }
+
       section('Check profile, release builds has Dart AOT dylib');
 
       for (String mode in <String>['Profile', 'Release']) {
@@ -116,6 +131,10 @@
           throw TaskResult.failure('$mode App.framework arm64 architecture missing');
         }
 
+        if (aotSymbols.contains('x86_64')) {
+          throw TaskResult.failure('$mode App.framework contains x86_64 architecture');
+        }
+
         if (!aotSymbols.contains('_kDartVmSnapshot')) {
           throw TaskResult.failure('$mode App.framework missing Dart AOT');
         }
diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart
index ccadbc7..a2dd4c9 100644
--- a/dev/devicelab/lib/framework/ios.dart
+++ b/dev/devicelab/lib/framework/ios.dart
@@ -53,3 +53,7 @@
 Future<String> dylibSymbols(String pathToDylib) {
   return eval('nm', <String>['-g', pathToDylib]);
 }
+
+Future<String> fileType(String pathToDylib) {
+  return eval('file', <String>[pathToDylib]);
+}
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index 845eb11..0d02f56 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -242,8 +242,16 @@
 
     const String embedBitcodeArg = '-fembed-bitcode';
     final String assemblyO = fs.path.join(outputPath, 'snapshot_assembly.o');
+    List<String> isysrootArgs;
+    if (isIOS) {
+      final String iPhoneSDKLocation = await xcode.sdkLocation(SdkType.iPhone);
+      if (iPhoneSDKLocation != null) {
+        isysrootArgs = <String>['-isysroot', iPhoneSDKLocation];
+      }
+    }
     final RunResult compileResult = await xcode.cc(<String>[
       '-arch', targetArch,
+      if (isysrootArgs != null) ...isysrootArgs,
       if (bitcode) embedBitcodeArg,
       '-c',
       assemblyPath,
@@ -265,7 +273,7 @@
       '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
       '-install_name', '@rpath/App.framework/App',
       if (bitcode) embedBitcodeArg,
-      if (bitcode && isIOS) ...<String>[embedBitcodeArg, '-isysroot', await xcode.iPhoneSdkLocation()],
+      if (isysrootArgs != null) ...isysrootArgs,
       '-o', appLib,
       assemblyO,
     ];
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 140ec2b..cf0b920 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
@@ -157,17 +157,11 @@
 /// This framework needs to exist for the Xcode project to link/bundle,
 /// but it isn't actually executed. To generate something valid, we compile a trivial
 /// constant.
-Future<RunResult> createStubAppFramework(Directory appFrameworkDirectory) async {
-  File outputFile;
+Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk) async {
   try {
-    if (!appFrameworkDirectory.existsSync()) {
-      appFrameworkDirectory.createSync(recursive: true);
-    }
-
-    outputFile = appFrameworkDirectory.childFile('App');
     outputFile.createSync(recursive: true);
   } catch (e) {
-    throwToolExit('Failed to create App.framework stub at ${appFrameworkDirectory.path}');
+    throwToolExit('Failed to create App.framework stub at ${outputFile.path}');
   }
 
   final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_stub_source.');
@@ -177,14 +171,32 @@
   static const int Moo = 88;
   ''');
 
+    List<String> archFlags;
+    if (sdk == SdkType.iPhone) {
+      archFlags = <String>[
+        '-arch',
+        getNameForDarwinArch(DarwinArch.armv7),
+        '-arch',
+        getNameForDarwinArch(DarwinArch.arm64),
+      ];
+    } else {
+      archFlags = <String>[
+        '-arch',
+        getNameForDarwinArch(DarwinArch.x86_64),
+      ];
+    }
+
     return await xcode.clang(<String>[
       '-x',
       'c',
+      ...archFlags,
       stubSource.path,
       '-dynamiclib',
+      '-fembed-bitcode-marker',
       '-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
       '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
       '-install_name', '@rpath/App.framework/App',
+      '-isysroot', await xcode.sdkLocation(sdk),
       '-o', outputFile.path,
     ]);
   } finally {
@@ -192,6 +204,8 @@
       tempDir.deleteSync(recursive: true);
     } on FileSystemException catch (_) {
       // Best effort. Sometimes we can't delete things from system temp.
+    } catch (e) {
+      throwToolExit('Failed to create App.framework stub at ${outputFile.path}');
     }
   }
 }
diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
index aeaa0a5..ca59fd5 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -167,7 +167,7 @@
       await _produceFlutterFramework(outputDirectory, mode, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory);
 
       // Build aot, create module.framework and copy.
-      await _produceAppFramework(mode, iPhoneBuildOutput, modeDirectory);
+      await _produceAppFramework(mode, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory);
 
       // Build and copy plugins.
       await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), mode);
@@ -255,13 +255,14 @@
     status.stop();
   }
 
-  Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory modeDirectory) async {
+  Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async {
     const String appFrameworkName = 'App.framework';
     final Directory destinationAppFrameworkDirectory = modeDirectory.childDirectory(appFrameworkName);
+    destinationAppFrameworkDirectory.createSync(recursive: true);
 
     if (mode == BuildMode.debug) {
       final Status status = logger.startProgress(' ├─Add placeholder App.framework for debug...', timeout: timeoutConfiguration.fastOperation);
-      await createStubAppFramework(destinationAppFrameworkDirectory);
+      await _produceStubAppFrameworkIfNeeded(mode, iPhoneBuildOutput, simulatorBuildOutput, destinationAppFrameworkDirectory);
       status.stop();
     } else {
       await _produceAotAppFrameworkIfNeeded(mode, iPhoneBuildOutput, destinationAppFrameworkDirectory);
@@ -284,6 +285,37 @@
     status.stop();
   }
 
+  Future<void> _produceStubAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory destinationAppFrameworkDirectory) async {
+    if (mode != BuildMode.debug) {
+      return;
+    }
+    const String appFrameworkName = 'App.framework';
+    const String binaryName = 'App';
+
+    final Directory iPhoneAppFrameworkDirectory = iPhoneBuildOutput.childDirectory(appFrameworkName);
+    final File iPhoneAppFrameworkFile = iPhoneAppFrameworkDirectory.childFile(binaryName);
+    await createStubAppFramework(iPhoneAppFrameworkFile, SdkType.iPhone);
+
+    final Directory simulatorAppFrameworkDirectory = simulatorBuildOutput.childDirectory(appFrameworkName);
+    final File simulatorAppFrameworkFile = simulatorAppFrameworkDirectory.childFile(binaryName);
+    await createStubAppFramework(simulatorAppFrameworkFile, SdkType.iPhoneSimulator);
+
+    final List<String> lipoCommand = <String>[
+      'xcrun',
+      'lipo',
+      '-create',
+      iPhoneAppFrameworkFile.path,
+      simulatorAppFrameworkFile.path,
+      '-output',
+      destinationAppFrameworkDirectory.childFile(binaryName).path
+    ];
+
+    await processUtils.run(
+      lipoCommand,
+      allowReentrantFlutter: false,
+    );
+  }
+
   Future<void> _produceAotAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory destinationAppFrameworkDirectory) async {
     if (mode == BuildMode.debug) {
       return;
@@ -296,6 +328,7 @@
       // Relative paths show noise in the compiler https://github.com/dart-lang/sdk/issues/37978.
       mainDartFile: fs.path.absolute(targetFile),
       quiet: true,
+      bitcode: true,
       reportTimings: false,
       iosBuildArchs: <DarwinArch>[DarwinArch.armv7, DarwinArch.arm64],
       dartDefines: dartDefines,
diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart
index 87cbc26..67695ca 100644
--- a/packages/flutter_tools/lib/src/commands/upgrade.dart
+++ b/packages/flutter_tools/lib/src/commands/upgrade.dart
@@ -68,7 +68,6 @@
   }
 }
 
-
 @visibleForTesting
 class UpgradeCommandRunner {
   Future<FlutterCommandResult> runCommand(
@@ -125,7 +124,8 @@
     final bool alreadyUpToDate = await attemptFastForward(flutterVersion);
     if (alreadyUpToDate) {
       // If the upgrade was a no op, then do not continue with the second half.
-      printTrace('Flutter is already up to date on channel ${flutterVersion.channel}');
+      printStatus('Flutter is already up to date on channel ${flutterVersion.channel}');
+      printStatus('$flutterVersion');
     } else {
       await flutterUpgradeContinue();
     }
diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart
index 515e6bb..d198087 100644
--- a/packages/flutter_tools/lib/src/macos/xcode.dart
+++ b/packages/flutter_tools/lib/src/macos/xcode.dart
@@ -17,6 +17,31 @@
 
 Xcode get xcode => context.get<Xcode>();
 
+enum SdkType {
+  iPhone,
+  iPhoneSimulator,
+  macOS,
+}
+
+/// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode
+/// SUPPORTED_PLATFORMS values.
+///
+/// Usage: xcrun [options] <tool name> ... arguments ...
+/// ...
+/// --sdk <sdk name>            find the tool for the given SDK name
+String getNameForSdk(SdkType sdk) {
+  switch (sdk) {
+    case SdkType.iPhone:
+      return 'iphoneos';
+    case SdkType.iPhoneSimulator:
+      return 'iphonesimulator';
+    case SdkType.macOS:
+      return 'macosx';
+  }
+  assert(false);
+  return null;
+}
+
 class Xcode {
   bool get isInstalledAndMeetsVersionCheck => platform.isMacOS && isInstalled && isVersionSatisfactory;
 
@@ -117,9 +142,10 @@
     );
   }
 
-  Future<String> iPhoneSdkLocation() async {
+  Future<String> sdkLocation(SdkType sdk) async {
+    assert(sdk != null);
     final RunResult runResult = await processUtils.run(
-      <String>['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'],
+      <String>['xcrun', '--sdk', getNameForSdk(sdk), '--show-sdk-path'],
       throwOnError: true,
     );
     if (runResult.exitCode != 0) {
diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
index 487b7b4..e3112a4 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
@@ -140,6 +140,7 @@
         environment: anyNamed('environment'),
         workingDirectory: anyNamed('workingDirectory'),
       ));
+      expect(testLogger.statusText, contains('Flutter is already up to date'));
     }, overrides: <Type, Generator>{
       ProcessManager: () => processManager,
       Platform: () => fakePlatform,
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 76f1daa..a7b3902 100644
--- a/packages/flutter_tools/test/general.shard/base/build_test.dart
+++ b/packages/flutter_tools/test/general.shard/base/build_test.dart
@@ -214,6 +214,7 @@
 
   group('Snapshotter - AOT', () {
     const String kSnapshotDart = 'snapshot.dart';
+    const String kSDKPath = '/path/to/sdk';
     String skyEnginePath;
 
     _FakeGenSnapshot genSnapshot;
@@ -243,6 +244,8 @@
       mockAndroidSdk = MockAndroidSdk();
       mockArtifacts = MockArtifacts();
       mockXcode = MockXcode();
+      when(mockXcode.sdkLocation(any)).thenAnswer((_) => Future<String>.value(kSDKPath));
+
       bufferLogger = BufferLogger();
       for (BuildMode mode in BuildMode.values) {
         when(mockArtifacts.getArtifactPath(Artifact.snapshotDart,
@@ -334,8 +337,19 @@
         'main.dill',
       ]);
 
-      verify(xcode.cc(argThat(contains('-fembed-bitcode')))).called(1);
-      verify(xcode.clang(argThat(contains('-fembed-bitcode')))).called(1);
+      final VerificationResult toVerifyCC = verify(xcode.cc(captureAny));
+      expect(toVerifyCC.callCount, 1);
+      final dynamic ccArgs = toVerifyCC.captured.first;
+      expect(ccArgs, contains('-fembed-bitcode'));
+      expect(ccArgs, contains('-isysroot'));
+      expect(ccArgs, contains(kSDKPath));
+
+      final VerificationResult toVerifyClang = verify(xcode.clang(captureAny));
+      expect(toVerifyClang.callCount, 1);
+      final dynamic clangArgs = toVerifyClang.captured.first;
+      expect(clangArgs, contains('-fembed-bitcode'));
+      expect(clangArgs, contains('-isysroot'));
+      expect(clangArgs, contains(kSDKPath));
 
       final File assemblyFile = fs.file(assembly);
       expect(assemblyFile.existsSync(), true);
@@ -380,8 +394,19 @@
         'main.dill',
       ]);
 
-      verify(xcode.cc(argThat(contains('-fembed-bitcode')))).called(1);
-      verify(xcode.clang(argThat(contains('-fembed-bitcode')))).called(1);
+      final VerificationResult toVerifyCC = verify(xcode.cc(captureAny));
+      expect(toVerifyCC.callCount, 1);
+      final dynamic ccArgs = toVerifyCC.captured.first;
+      expect(ccArgs, contains('-fembed-bitcode'));
+      expect(ccArgs, contains('-isysroot'));
+      expect(ccArgs, contains(kSDKPath));
+
+      final VerificationResult toVerifyClang = verify(xcode.clang(captureAny));
+      expect(toVerifyClang.callCount, 1);
+      final dynamic clangArgs = toVerifyClang.captured.first;
+      expect(clangArgs, contains('-fembed-bitcode'));
+      expect(clangArgs, contains('-isysroot'));
+      expect(clangArgs, contains(kSDKPath));
 
       final File assemblyFile = fs.file(assembly);
       final File assemblyBitcodeFile = fs.file('$assembly.stripped.S');
@@ -431,6 +456,9 @@
       verifyNever(xcode.cc(argThat(contains('-fembed-bitcode'))));
       verifyNever(xcode.clang(argThat(contains('-fembed-bitcode'))));
 
+      verify(xcode.cc(argThat(contains('-isysroot')))).called(1);
+      verify(xcode.clang(argThat(contains('-isysroot')))).called(1);
+
       final File assemblyFile = fs.file(assembly);
       expect(assemblyFile.existsSync(), true);
       expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart
index 378884b..ecbd244 100644
--- a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart
+++ b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart
@@ -190,5 +190,11 @@
     }, overrides: <Type, Generator>{
       ProcessManager: () => mockProcessManager,
     });
+
+    testUsingContext('SDK name', () {
+      expect(getNameForSdk(SdkType.iPhone), 'iphoneos');
+      expect(getNameForSdk(SdkType.iPhoneSimulator), 'iphonesimulator');
+      expect(getNameForSdk(SdkType.macOS), 'macosx');
+    });
   });
 }