Skip to content

Commit 1561b65

Browse files
add gradle error handler for when the remote ssl host terminates handshake process (#125270)
Will fix transient network failures as in: flutter/flutter#125108 (comment)
1 parent d93ffc1 commit 1561b65

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

packages/flutter_tools/lib/src/android/gradle.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
205205
isBuildingBundle: false,
206206
localGradleErrors: gradleErrors,
207207
configOnly: configOnly,
208+
maxRetries: 1,
208209
);
209210
}
210211

@@ -227,6 +228,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
227228
validateDeferredComponents: validateDeferredComponents,
228229
deferredComponentsEnabled: deferredComponentsEnabled,
229230
configOnly: configOnly,
231+
maxRetries: 1,
230232
);
231233
}
232234

packages/flutter_tools/lib/src/android/gradle_errors.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
8484
sslExceptionHandler,
8585
zipExceptionHandler,
8686
incompatibleJavaAndGradleVersionsHandler,
87+
remoteTerminatedHandshakeHandler,
8788
];
8889

8990
const String _boxTitle = 'Flutter Fix';
@@ -700,3 +701,22 @@ final GradleHandledError incompatibleJavaAndGradleVersionsHandler = GradleHandle
700701
},
701702
eventLabel: 'incompatible-java-gradle-version',
702703
);
704+
705+
@visibleForTesting
706+
final GradleHandledError remoteTerminatedHandshakeHandler = GradleHandledError(
707+
test: (String line) => line.contains('Remote host terminated the handshake'),
708+
handler: ({
709+
required String line,
710+
required FlutterProject project,
711+
required bool usesAndroidX,
712+
required bool multidexEnabled,
713+
}) async {
714+
globals.printError(
715+
'${globals.logger.terminal.warningMark} '
716+
'Gradle threw an error while downloading artifacts from the network.'
717+
);
718+
719+
return GradleBuildStatus.retry;
720+
},
721+
eventLabel: 'remote-terminated-handshake',
722+
);

packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void main() {
4949
sslExceptionHandler,
5050
zipExceptionHandler,
5151
incompatibleJavaAndGradleVersionsHandler,
52+
remoteTerminatedHandshakeHandler,
5253
])
5354
);
5455
});
@@ -88,6 +89,50 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
8889
ProcessManager: () => processManager,
8990
});
9091

92+
testUsingContext('retries if remote host terminated ssl handshake', () async {
93+
const String errorMessage = r'''
94+
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
95+
at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1696)
96+
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1514)
97+
at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1416)
98+
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:456)
99+
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:427)
100+
at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:572)
101+
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:197)
102+
at java.base/sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2783)
103+
at java.base/sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2695)
104+
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1854)
105+
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1520)
106+
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:250)
107+
at org.gradle.wrapper.Download.downloadInternal(Download.java:58)
108+
at org.gradle.wrapper.Download.download(Download.java:44)
109+
at org.gradle.wrapper.Install$1.call(Install.java:61)
110+
at org.gradle.wrapper.Install$1.call(Install.java:48)
111+
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65)
112+
at org.gradle.wrapper.Install.createDist(Install.java:48)
113+
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
114+
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)
115+
Caused by: java.io.EOFException: SSL peer shut down incorrectly
116+
at java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:483)
117+
at java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:472)
118+
at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:160)
119+
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:111)
120+
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1506)''';
121+
122+
expect(formatTestErrorMessage(errorMessage, remoteTerminatedHandshakeHandler), isTrue);
123+
expect(await remoteTerminatedHandshakeHandler.handler(
124+
line: '',
125+
multidexEnabled: true,
126+
project: FakeFlutterProject(),
127+
usesAndroidX: true,
128+
), equals(GradleBuildStatus.retry));
129+
130+
expect(testLogger.errorText,
131+
contains(
132+
'Gradle threw an error while downloading artifacts from the network.'
133+
)
134+
);
135+
});
91136
testUsingContext('retries if gradle fails downloading with proxy error', () async {
92137
const String errorMessage = r'''
93138
Exception in thread "main" java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"

0 commit comments

Comments
 (0)