Commit aa9c7826 authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Add initial list of known Android hardware (#10249)

Our emulator detection was based on a simple heuristic that was
failing for the Samsung Galaxy S8. Any heuristic is flawed since
Android devices can report whatever they want to adb, but this
change attempts to tighten the detection by listing known models
(by their ro.hardware property). Again, these values could be
spoofed by emulator system images, but it's less likely to be
an issue than with our previous (and fall-back) heuristic.

Fixes #10203
Related: #10248
parent e3ae11e8
......@@ -27,6 +27,17 @@ import 'android_sdk.dart';
const String _defaultAdbPath = 'adb';
enum _HardwareType { emulator, physical }
/// Map to help our `isLocalEmulator` detection.
const Map<String, _HardwareType> _knownHardware = const <String, _HardwareType>{
'goldfish': _HardwareType.emulator,
'qcom': _HardwareType.physical,
'ranchu': _HardwareType.emulator,
'samsungexynos7420': _HardwareType.physical,
'samsungexynos8895': _HardwareType.physical,
};
class AndroidDevices extends PollingDeviceDiscovery {
AndroidDevices() : super('Android devices');
......@@ -90,8 +101,17 @@ class AndroidDevice extends Device {
@override
Future<bool> get isLocalEmulator async {
if (_isLocalEmulator == null) {
final String characteristics = await _getProperty('ro.build.characteristics');
_isLocalEmulator = characteristics != null && characteristics.contains('emulator');
final String hardware = await _getProperty('ro.hardware');
printTrace('ro.hardware = $hardware');
if (_knownHardware.containsKey(hardware)) {
// Look for known hardware models.
_isLocalEmulator = _knownHardware[hardware] == _HardwareType.emulator;
} else {
// Fall back to a best-effort heuristic-based approach.
final String characteristics = await _getProperty('ro.build.characteristics');
printTrace('ro.build.characteristics = $characteristics');
_isLocalEmulator = characteristics != null && characteristics.contains('emulator');
}
}
return _isLocalEmulator;
}
......
......@@ -2,7 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:test/test.dart';
import '../src/context.dart';
......@@ -68,8 +73,60 @@ Use the 'android' tool to install them:
expect(properties['ro.build.version.sdk'], '23');
});
});
group('isLocalEmulator', () {
final ProcessManager mockProcessManager = new MockProcessManager();
String hardware;
String buildCharacteristics;
setUp(() {
hardware = 'unknown';
buildCharacteristics = 'unused';
when(mockProcessManager.run(argThat(contains('getprop')), stderrEncoding: any, stdoutEncoding: any)).thenAnswer((_) {
final StringBuffer buf = new StringBuffer()
..writeln('[ro.hardware]: [$hardware]')
..writeln('[ro.build.characteristics]: [$buildCharacteristics]');
final ProcessResult result = new ProcessResult(1, 0, buf.toString(), '');
return new Future<ProcessResult>.value(result);
});
});
testUsingContext('knownPhysical', () async {
hardware = 'samsungexynos7420';
final AndroidDevice device = new AndroidDevice('test');
expect(await device.isLocalEmulator, false);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('knownEmulator', () async {
hardware = 'goldfish';
final AndroidDevice device = new AndroidDevice('test');
expect(await device.isLocalEmulator, true);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('unknownPhysical', () async {
buildCharacteristics = 'att';
final AndroidDevice device = new AndroidDevice('test');
expect(await device.isLocalEmulator, false);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('unknownEmulator', () async {
buildCharacteristics = 'att,emulator';
final AndroidDevice device = new AndroidDevice('test');
expect(await device.isLocalEmulator, true);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
});
}
class MockProcessManager extends Mock implements ProcessManager {}
const String kAdbShellGetprop = '''
[dalvik.vm.dex2oat-Xms]: [64m]
[dalvik.vm.dex2oat-Xmx]: [512m]
......
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