Introduce a quick way to test across platforms (#8262)

diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index d207ffd..2450bd5 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -111,24 +111,26 @@
     Status status = logger.startProgress('Taking screenshot...');
     File outputFile = getUniqueFile(fs.currentDirectory, 'flutter', 'png');
     try {
-      if (vmService != null)
-        await vmService.vm.refreshViews();
-      try {
-        if (isRunningDebug)
+      if (supportsServiceProtocol && isRunningDebug) {
+        if (vmService != null)
+          await vmService.vm.refreshViews();
+        try {
           await currentView.uiIsolate.flutterDebugAllowBanner(false);
-      } catch (error) {
-        status.stop();
-        printError(error);
+        } catch (error) {
+          status.stop();
+          printError(error);
+        }
       }
       try {
         await device.takeScreenshot(outputFile);
       } finally {
-        try {
-          if (isRunningDebug)
+        if (supportsServiceProtocol && isRunningDebug) {
+          try {
             await currentView.uiIsolate.flutterDebugAllowBanner(true);
-        } catch (error) {
-          status.stop();
-          printError(error);
+          } catch (error) {
+            status.stop();
+            printError(error);
+          }
         }
       }
       int sizeKB = (await outputFile.length()) ~/ 1024;
@@ -140,6 +142,18 @@
     }
   }
 
+  Future<String> _debugRotatePlatform() async {
+    if (vmService != null)
+      await vmService.vm.refreshViews();
+    switch (await currentView.uiIsolate.flutterPlatformOverride()) {
+      case 'iOS':
+        return await currentView.uiIsolate.flutterPlatformOverride('android');
+      case 'android':
+      default:
+        return await currentView.uiIsolate.flutterPlatformOverride('iOS');
+    }
+  }
+
   void registerSignalHandlers() {
     assert(stayResident);
     ProcessSignal.SIGINT.watch().listen(_cleanUpAndExit);
@@ -228,25 +242,31 @@
       printHelp(details: true);
       return true;
     } else if (lower == 'w') {
-      if (!supportsServiceProtocol)
+      if (supportsServiceProtocol) {
+        await _debugDumpApp();
         return true;
-      await _debugDumpApp();
-      return true;
+      }
     } else if (lower == 't') {
-      if (!supportsServiceProtocol)
+      if (supportsServiceProtocol) {
+        await _debugDumpRenderTree();
         return true;
-      await _debugDumpRenderTree();
-      return true;
+      }
     } else if (lower == 'p') {
-      if (!supportsServiceProtocol)
+      if (supportsServiceProtocol && isRunningDebug) {
+        await _debugToggleDebugPaintSizeEnabled();
         return true;
-      await _debugToggleDebugPaintSizeEnabled();
-      return true;
+      }
     } else if (lower == 's') {
-      if (!supportsServiceProtocol || !device.supportsScreenshot)
+      if (device.supportsScreenshot) {
+        await _screenshot();
         return true;
-      await _screenshot();
-      return true;
+      }
+    } else if (lower == 'o') {
+      if (supportsServiceProtocol && isRunningDebug) {
+        String platform = await _debugRotatePlatform();
+        print('Switched operating system to: $platform');
+        return true;
+      }
     } else if (lower == 'q' || character == AnsiTerminal.KEY_F10) {
       // F10, exit
       await stop();
@@ -347,7 +367,10 @@
     if (supportsServiceProtocol) {
       printStatus('To dump the widget hierarchy of the app (debugDumpApp), press "w".');
       printStatus('To dump the rendering tree of the app (debugDumpRenderTree), press "t".');
-      printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".');
+      if (isRunningDebug) {
+        printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".');
+        printStatus('To simulate different operating systems, (defaultTargetPlatform), press "o".');
+      }
     }
     if (device.supportsScreenshot)
       printStatus('To save a screenshot to flutter.png, press "s".');
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 95a9bb6..b3114d8 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -924,6 +924,18 @@
       timeoutFatal: false,
     );
   }
+
+  Future<Null> flutterPlatformOverride([String platform]) async {
+    Map<String, String> result = await invokeFlutterExtensionRpcRaw(
+      'ext.flutter.platformOverride',
+      params: platform != null ? <String, dynamic>{ 'value': platform } : <String, String>{},
+      timeout: const Duration(seconds: 5),
+      timeoutFatal: false,
+    );
+    if (result != null && result.containsKey('value') && result['value'] is String)
+      return result['value'];
+    return 'unknown';
+  }
 }
 
 class ServiceMap extends ServiceObject implements Map<String, dynamic> {