Add DevicePortForwarder

This commit is contained in:
John McCutchan 2016-03-08 14:27:12 -08:00
parent c2b175d1db
commit 131359f4bc
4 changed files with 176 additions and 11 deletions

View file

@ -51,6 +51,7 @@ class AndroidDevice extends Device {
bool get isLocalEmulator => false;
_AdbLogReader _logReader;
_AndroidDevicePortForwarder _portForwarder;
List<String> adbCommandForDevice(List<String> args) {
return <String>[androidSdk.adbPath, '-s', id]..addAll(args);
@ -169,19 +170,10 @@ class AndroidDevice extends Device {
Future _forwardObservatoryPort(int port) async {
bool portWasZero = port == 0;
if (port == 0) {
// Auto-bind to a port. Set up forwarding for that port. Emit a stdout
// message similar to the command-line VM so that tools can parse the output.
// "Observatory listening on http://127.0.0.1:52111"
port = await findAvailablePort();
}
try {
// Set up port forwarding for observatory.
runCheckedSync(adbCommandForDevice(<String>[
'forward', 'tcp:$port', 'tcp:$observatoryDefaultPort'
]));
port = await portForwarder.forward(observatoryDefaultPort,
hostPort: port);
if (portWasZero)
printStatus('Observatory listening on http://127.0.0.1:$port');
} catch (e) {
@ -292,6 +284,13 @@ class AndroidDevice extends Device {
return _logReader;
}
DevicePortForwarder get portForwarder {
if (_portForwarder == null)
_portForwarder = new _AndroidDevicePortForwarder(this);
return _portForwarder;
}
void startTracing(AndroidApk apk) {
runCheckedSync(adbCommandForDevice(<String>[
'shell',
@ -537,3 +536,74 @@ class _AdbLogReader extends DeviceLogReader {
return other.device.id == device.id;
}
}
class _AndroidDevicePortForwarder extends DevicePortForwarder {
_AndroidDevicePortForwarder(this.device);
final AndroidDevice device;
static int _extractPort(String portString) {
return int.parse(portString.trim(), onError: (_) => null);
}
List<ForwardedPort> get forwardedPorts {
final List<ForwardedPort> ports = <ForwardedPort>[];
String stdout = runCheckedSync(
<String>[
androidSdk.adbPath,
'forward',
'--list'
]);
List<String> lines = LineSplitter.split(stdout).toList();
for (String line in lines) {
if (line.startsWith(device.id)) {
List<String> splitLine = line.split("tcp:");
// Sanity check splitLine.
if (splitLine.length != 3)
continue;
// Attempt to extract ports.
int hostPort = _extractPort(splitLine[1]);
int devicePort = _extractPort(splitLine[2]);
// Failed, skip.
if ((hostPort == null) || (devicePort == null))
continue;
ports.add(new ForwardedPort(hostPort, devicePort));
}
}
return ports;
}
Future<int> forward(int devicePort, {int hostPort: null}) async {
if ((hostPort == null) || (hostPort == 0)) {
// Auto select host port.
hostPort = await findAvailablePort();
}
runCheckedSync(
<String>[
androidSdk.adbPath,
'forward',
hostPort.toString(),
devicePort.toString()
]);
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
runCheckedSync(
<String>[
androidSdk.adbPath,
'forward',
'--remove',
forwardedPort.hostPort.toString()
]);
}
}

View file

@ -151,6 +151,9 @@ abstract class Device {
/// Get the log reader for this device.
DeviceLogReader get logReader;
/// Get the port forwarder for this device.
DevicePortForwarder get portForwarder;
/// Clear the device's logs.
void clearLogs();
@ -186,6 +189,30 @@ abstract class Device {
String toString() => '$runtimeType $id';
}
class ForwardedPort {
ForwardedPort(this.hostPort, this.devicePort);
final int hostPort;
final int devicePort;
String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
}
/// Forward ports from the host machine to the device.
abstract class DevicePortForwarder {
/// Returns a Future that completes with the current list of forwarded
/// ports for this device.
List<ForwardedPort> get forwardedPorts;
/// Forward [hostPort] on the host to [devicePort] on the device.
/// If [hostPort] is null, will auto select a host port.
/// Returns a Future that completes with the host port.
Future<int> forward(int devicePort, {int hostPort: null});
/// Stops forwarding [forwardedPort].
Future unforward(ForwardedPort forwardedPort);
}
/// Read the log for a particular device. Subclasses must implement `hashCode`
/// and `operator ==` so that log readers that read from the same location can be
/// de-duped. For example, two Android devices will both try and log using

View file

@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
import '../application_package.dart';
import '../base/common.dart';
import '../base/os.dart';
import '../base/process.dart';
import '../build_configuration.dart';
import '../device.dart';
@ -65,6 +66,8 @@ class IOSDevice extends Device {
_IOSDeviceLogReader _logReader;
_IOSDevicePortForwarder _portForwarder;
bool get isLocalEmulator => false;
bool get supportsStartPaused => false;
@ -230,6 +233,13 @@ class IOSDevice extends Device {
return _logReader;
}
DevicePortForwarder get portForwarder {
if (_portForwarder == null)
_portForwarder = new _IOSDevicePortForwarder(this);
return _portForwarder;
}
void clearLogs() {
}
}
@ -310,3 +320,28 @@ class _IOSDeviceLogReader extends DeviceLogReader {
return other.name == name;
}
}
class _IOSDevicePortForwarder extends DevicePortForwarder {
_IOSDevicePortForwarder(this.device);
final IOSDevice device;
List<ForwardedPort> get forwardedPorts {
final List<ForwardedPort> ports = <ForwardedPort>[];
// TODO(chinmaygarde): Implement.
return ports;
}
Future<int> forward(int devicePort, {int hostPort: null}) async {
if ((hostPort == null) || (hostPort == 0)) {
// Auto select host port.
hostPort = await findAvailablePort();
}
// TODO(chinmaygarde): Implement.
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
// TODO(chinmaygarde): Implement.
}
}

View file

@ -321,6 +321,7 @@ class IOSSimulator extends Device {
bool get isLocalEmulator => true;
_IOSSimulatorLogReader _logReader;
_IOSSimulatorDevicePortForwarder _portForwarder;
String get xcrunPath => path.join('/usr', 'bin', 'xcrun');
@ -544,6 +545,13 @@ class IOSSimulator extends Device {
return _logReader;
}
DevicePortForwarder get portForwarder {
if (_portForwarder == null)
_portForwarder = new _IOSSimulatorDevicePortForwarder(this);
return _portForwarder;
}
void clearLogs() {
File logFile = new File(logFilePath);
if (logFile.existsSync()) {
@ -772,3 +780,28 @@ int compareIphoneVersions(String id1, String id2) {
int q2 = qualifiers.indexOf(m2[2]);
return q1.compareTo(q2);
}
class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {
_IOSSimulatorDevicePortForwarder(this.device);
final IOSSimulator device;
final List<ForwardedPort> _ports = <ForwardedPort>[];
List<ForwardedPort> get forwardedPorts {
return _ports;
}
Future<int> forward(int devicePort, {int hostPort: null}) async {
if ((hostPort == null) || (hostPort == 0)) {
hostPort = devicePort;
}
assert(devicePort == hostPort);
_ports.add(new ForwardedPort(devicePort, hostPort));
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
_ports.remove(forwardedPort);
}
}