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 {
];
// logcat -T is not supported on Android releases before Lollipop.
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) {
args.addAll(<String>[
'-T',
......
......@@ -698,67 +698,88 @@ flutter:
setUp(() {
mockAndroidSdk = MockAndroidSdk();
mockProcessManager = MockProcessManager();
});
void setupGetprop({int apiVersion}) {
when(mockProcessManager.run(
argThat(contains('getprop')),
stderrEncoding: anyNamed('stderrEncoding'),
stdoutEncoding: anyNamed('stdoutEncoding'),
)).thenAnswer((_) {
final StringBuffer buf = StringBuffer()
..writeln('[ro.build.version.sdk]: [28]');
final ProcessResult result = ProcessResult(1, 0, buf.toString(), '');
final String buf = apiVersion == null
? ''
: '[ro.build.version.sdk]: [$apiVersion]\n';
final ProcessResult result = ProcessResult(1, 0, buf, '');
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>();
when(mockProcessManager.start(argThat(contains('logcat'))))
.thenAnswer((_) {
logcatCompleter.complete();
return Future<Process>.value(createMockProcess());
});
const int kLollipopVersionCode = 21;
void callsAdbLogcatCorrectly({int apiVersion}) {
testUsingContext('calls adb logcat with expected flags, apiVersion=$apiVersion', () async {
const String kLastLogcatTimestamp = '11-27 15:39:04.506';
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');
final DeviceLogReader logReader = device.getLogReader();
logReader.logLines.listen((_) {});
await logcatCompleter.future;
testUsingContext('calls adb logcat with expected flags when the device logs are empty, apiVersion=$apiVersion', () async {
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, '', ''));
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', '']))
.called(1);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
ProcessManager: () => mockProcessManager,
});
callsAdbLogcatCorrectly(apiVersion: kLollipopVersionCode);
callsAdbLogcatCorrectly(apiVersion: kLollipopVersionCode - 1);
callsAdbLogcatCorrectly();
});
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