Unverified Commit ef62d532 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

[flutter_tools] Fix crash on null Android apiVersion (#50029)

parent abf4e161
...@@ -1040,7 +1040,11 @@ class _AdbLogReader extends DeviceLogReader { ...@@ -1040,7 +1040,11 @@ class _AdbLogReader extends DeviceLogReader {
]; ];
// logcat -T is not supported on Android releases before Lollipop. // logcat -T is not supported on Android releases before Lollipop.
const int kLollipopVersionCode = 21; const int kLollipopVersionCode = 21;
final int apiVersion = int.tryParse(await device._apiVersion); final int apiVersion = (String v) {
// If the API version string isn't found, conservatively assume that the
// version is less recent than the one we're looking for.
return v == null ? kLollipopVersionCode - 1 : int.tryParse(v);
}(await device._apiVersion);
if (apiVersion != null && apiVersion >= kLollipopVersionCode) { if (apiVersion != null && apiVersion >= kLollipopVersionCode) {
args.addAll(<String>[ args.addAll(<String>[
'-T', '-T',
......
...@@ -698,67 +698,88 @@ flutter: ...@@ -698,67 +698,88 @@ flutter:
setUp(() { setUp(() {
mockAndroidSdk = MockAndroidSdk(); mockAndroidSdk = MockAndroidSdk();
mockProcessManager = MockProcessManager(); mockProcessManager = MockProcessManager();
});
void setupGetprop({int apiVersion}) {
when(mockProcessManager.run( when(mockProcessManager.run(
argThat(contains('getprop')), argThat(contains('getprop')),
stderrEncoding: anyNamed('stderrEncoding'), stderrEncoding: anyNamed('stderrEncoding'),
stdoutEncoding: anyNamed('stdoutEncoding'), stdoutEncoding: anyNamed('stdoutEncoding'),
)).thenAnswer((_) { )).thenAnswer((_) {
final StringBuffer buf = StringBuffer() final String buf = apiVersion == null
..writeln('[ro.build.version.sdk]: [28]'); ? ''
final ProcessResult result = ProcessResult(1, 0, buf.toString(), ''); : '[ro.build.version.sdk]: [$apiVersion]\n';
final ProcessResult result = ProcessResult(1, 0, buf, '');
return Future<ProcessResult>.value(result); return Future<ProcessResult>.value(result);
}); });
}); }
testUsingContext('calls adb logcat with expected flags', () async {
const String kLastLogcatTimestamp = '11-27 15:39:04.506';
when(mockAndroidSdk.adbPath).thenReturn('adb');
when(mockProcessManager.runSync(<String>['adb', '-s', '1234', 'shell', '-x', 'logcat', '-v', 'time', '-t', '1']))
.thenReturn(ProcessResult(0, 0, '$kLastLogcatTimestamp I/flutter: irrelevant', ''));
final Completer<void> logcatCompleter = Completer<void>();
when(mockProcessManager.start(argThat(contains('logcat'))))
.thenAnswer((_) {
logcatCompleter.complete();
return Future<Process>.value(createMockProcess());
});
final AndroidDevice device = AndroidDevice('1234');
final DeviceLogReader logReader = device.getLogReader();
logReader.logLines.listen((_) {});
await logcatCompleter.future;
verify(mockProcessManager.start(const <String>['adb', '-s', '1234', 'logcat', '-v', 'time', '-T', kLastLogcatTimestamp]))
.called(1);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
ProcessManager: () => mockProcessManager,
});
testUsingContext('calls adb logcat with expected flags when the device logs are empty', () async {
when(mockAndroidSdk.adbPath).thenReturn('adb');
when(mockProcessManager.runSync(<String>['adb', '-s', '1234', 'shell', '-x', 'logcat', '-v', 'time', '-t', '1']))
.thenReturn(ProcessResult(0, 0, '', ''));
final Completer<void> logcatCompleter = Completer<void>(); const int kLollipopVersionCode = 21;
when(mockProcessManager.start(argThat(contains('logcat')))) void callsAdbLogcatCorrectly({int apiVersion}) {
.thenAnswer((_) { testUsingContext('calls adb logcat with expected flags, apiVersion=$apiVersion', () async {
logcatCompleter.complete(); const String kLastLogcatTimestamp = '11-27 15:39:04.506';
return Future<Process>.value(createMockProcess()); setupGetprop(apiVersion: apiVersion);
}); when(mockAndroidSdk.adbPath).thenReturn('adb');
when(mockProcessManager.runSync(<String>[
'adb', '-s', '1234', 'shell', '-x', 'logcat', '-v', 'time', '-t', '1',
]))
.thenReturn(ProcessResult(0, 0, '$kLastLogcatTimestamp I/flutter: irrelevant', ''));
final Completer<void> logcatCompleter = Completer<void>();
when(mockProcessManager.start(argThat(contains('logcat'))))
.thenAnswer((_) {
logcatCompleter.complete();
return Future<Process>.value(createMockProcess());
});
final AndroidDevice device = AndroidDevice('1234');
final DeviceLogReader logReader = device.getLogReader();
logReader.logLines.listen((_) {});
await logcatCompleter.future;
verify(mockProcessManager.start(<String>[
'adb', '-s', '1234', 'logcat', '-v', 'time',
if (apiVersion != null && apiVersion >= kLollipopVersionCode)
...<String>['-T', kLastLogcatTimestamp],
])).called(1);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
ProcessManager: () => mockProcessManager,
});
final AndroidDevice device = AndroidDevice('1234'); testUsingContext('calls adb logcat with expected flags when the device logs are empty, apiVersion=$apiVersion', () async {
final DeviceLogReader logReader = device.getLogReader(); setupGetprop(apiVersion: apiVersion);
logReader.logLines.listen((_) {}); when(mockAndroidSdk.adbPath).thenReturn('adb');
await logcatCompleter.future; when(mockProcessManager.runSync(<String>[
'adb', '-s', '1234', 'shell', '-x', 'logcat', '-v', 'time', '-t', '1',
])).thenReturn(ProcessResult(0, 0, '', ''));
final Completer<void> logcatCompleter = Completer<void>();
when(mockProcessManager.start(argThat(contains('logcat'))))
.thenAnswer((_) {
logcatCompleter.complete();
return Future<Process>.value(createMockProcess());
});
final AndroidDevice device = AndroidDevice('1234');
final DeviceLogReader logReader = device.getLogReader();
logReader.logLines.listen((_) {});
await logcatCompleter.future;
verify(mockProcessManager.start(<String>[
'adb', '-s', '1234', 'logcat', '-v', 'time',
if (apiVersion != null && apiVersion >= kLollipopVersionCode)
...<String>['-T', ''],
])).called(1);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
ProcessManager: () => mockProcessManager,
});
}
verify(mockProcessManager.start(const <String>['adb', '-s', '1234', 'logcat', '-v', 'time', '-T', ''])) callsAdbLogcatCorrectly(apiVersion: kLollipopVersionCode);
.called(1); callsAdbLogcatCorrectly(apiVersion: kLollipopVersionCode - 1);
}, overrides: <Type, Generator>{ callsAdbLogcatCorrectly();
AndroidSdk: () => mockAndroidSdk,
ProcessManager: () => mockProcessManager,
});
}); });
test('Can parse adb shell dumpsys info', () { test('Can parse adb shell dumpsys info', () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment