Prompt a solution message when flutter tools network fail in China (#16244)

diff --git a/packages/flutter_tools/test/cache_test.dart b/packages/flutter_tools/test/cache_test.dart
index fb8fd5c..9b382bc 100644
--- a/packages/flutter_tools/test/cache_test.dart
+++ b/packages/flutter_tools/test/cache_test.dart
@@ -11,6 +11,7 @@
 import 'package:platform/platform.dart';
 
 import 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
 
 import 'src/context.dart';
 
@@ -76,6 +77,31 @@
       verifyNever(artifact1.update());
       verify(artifact2.update());
     });
+    testUsingContext('failed storage.googleapis.com download shows China warning', () async {
+      final CachedArtifact artifact1 = new MockCachedArtifact();
+      final CachedArtifact artifact2 = new MockCachedArtifact();
+      when(artifact1.isUpToDate()).thenReturn(false);
+      when(artifact2.isUpToDate()).thenReturn(false);
+      final MockInternetAddress address = new MockInternetAddress();
+      when(address.host).thenReturn('storage.googleapis.com');
+      when(artifact1.update()).thenThrow(new SocketException(
+        'Connection reset by peer',
+        address: address,
+      ));
+      final Cache cache = new Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
+      try {
+        await cache.updateAll();
+        fail('Mock thrown exception expected');
+      } catch (e) {
+        verify(artifact1.update());
+        // Don't continue when retrieval fails.
+        verifyNever(artifact2.update());
+        expect(
+          testLogger.errorText,
+          contains('https://github.com/flutter/flutter/wiki/Using-Flutter-in-China'),
+        );
+      }
+    });
   });
 
   testUsingContext('flattenNameSubdirs', () {
@@ -103,3 +129,4 @@
 
 class MockRandomAccessFile extends Mock implements RandomAccessFile {}
 class MockCachedArtifact extends Mock implements CachedArtifact {}
+class MockInternetAddress extends Mock implements InternetAddress {}