Enable launching applications on the iOS device with observatory and diagnostics server connected. (#4424)
This commit is contained in:
parent
f92f71feb9
commit
9782d97faa
@ -307,10 +307,12 @@ class LaunchResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ForwardedPort {
|
class ForwardedPort {
|
||||||
ForwardedPort(this.hostPort, this.devicePort);
|
ForwardedPort(this.hostPort, this.devicePort) : context = null;
|
||||||
|
ForwardedPort.withContext(this.hostPort, this.devicePort, this.context);
|
||||||
|
|
||||||
final int hostPort;
|
final int hostPort;
|
||||||
final int devicePort;
|
final int devicePort;
|
||||||
|
final dynamic context;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
|
String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
|
||||||
|
@ -12,6 +12,8 @@ import '../base/process.dart';
|
|||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
|
import '../observatory.dart';
|
||||||
|
import '../protocol_discovery.dart';
|
||||||
import 'mac.dart';
|
import 'mac.dart';
|
||||||
|
|
||||||
const String _ideviceinstallerInstructions =
|
const String _ideviceinstallerInstructions =
|
||||||
@ -33,6 +35,7 @@ class IOSDevice extends Device {
|
|||||||
_installerPath = _checkForCommand('ideviceinstaller');
|
_installerPath = _checkForCommand('ideviceinstaller');
|
||||||
_listerPath = _checkForCommand('idevice_id');
|
_listerPath = _checkForCommand('idevice_id');
|
||||||
_informerPath = _checkForCommand('ideviceinfo');
|
_informerPath = _checkForCommand('ideviceinfo');
|
||||||
|
_iproxyPath = _checkForCommand('iproxy');
|
||||||
_debuggerPath = _checkForCommand('idevicedebug');
|
_debuggerPath = _checkForCommand('idevicedebug');
|
||||||
_loggerPath = _checkForCommand('idevicesyslog');
|
_loggerPath = _checkForCommand('idevicesyslog');
|
||||||
_pusherPath = _checkForCommand(
|
_pusherPath = _checkForCommand(
|
||||||
@ -52,6 +55,9 @@ class IOSDevice extends Device {
|
|||||||
String _informerPath;
|
String _informerPath;
|
||||||
String get informerPath => _informerPath;
|
String get informerPath => _informerPath;
|
||||||
|
|
||||||
|
String _iproxyPath;
|
||||||
|
String get iproxyPath => _iproxyPath;
|
||||||
|
|
||||||
String _debuggerPath;
|
String _debuggerPath;
|
||||||
String get debuggerPath => _debuggerPath;
|
String get debuggerPath => _debuggerPath;
|
||||||
|
|
||||||
@ -194,7 +200,20 @@ class IOSDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Attempt to install the application on the device.
|
// Step 3: Attempt to install the application on the device.
|
||||||
int installationResult = await runCommandAndStreamOutput(<String>[
|
List<String> launchArguments = <String>[];
|
||||||
|
|
||||||
|
if (debuggingOptions.startPaused)
|
||||||
|
launchArguments.add("--start-paused");
|
||||||
|
|
||||||
|
if (debuggingOptions.debuggingEnabled) {
|
||||||
|
launchArguments.add("--enable-checked-mode");
|
||||||
|
|
||||||
|
// Note: We do NOT need to set the observatory port since this is going to
|
||||||
|
// be setup on the device. Let it pick a port automatically. We will check
|
||||||
|
// the port picked and scrape that later.
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> launchCommand = <String>[
|
||||||
'/usr/bin/env',
|
'/usr/bin/env',
|
||||||
'ios-deploy',
|
'ios-deploy',
|
||||||
'--id',
|
'--id',
|
||||||
@ -202,14 +221,109 @@ class IOSDevice extends Device {
|
|||||||
'--bundle',
|
'--bundle',
|
||||||
bundle.path,
|
bundle.path,
|
||||||
'--justlaunch',
|
'--justlaunch',
|
||||||
], trace: true);
|
];
|
||||||
|
|
||||||
|
if (launchArguments.length > 0) {
|
||||||
|
launchCommand.add('--args');
|
||||||
|
launchCommand.add('"${launchArguments.join(" ")}"');
|
||||||
|
}
|
||||||
|
|
||||||
|
int installationResult = -1;
|
||||||
|
int localObsPort;
|
||||||
|
int localDiagPort;
|
||||||
|
|
||||||
|
if (!debuggingOptions.debuggingEnabled || mode == BuildMode.release) {
|
||||||
|
// If debugging is not enabled, just launch the application and continue.
|
||||||
|
printTrace("Debugging is not enabled");
|
||||||
|
installationResult = await runCommandAndStreamOutput(launchCommand, trace: true);
|
||||||
|
} else {
|
||||||
|
// Debugging is enabled, look for the observatory and diagnostic server
|
||||||
|
// ports post launch.
|
||||||
|
printTrace("Debugging is enabled, connecting to observatory and the diagnostic server");
|
||||||
|
|
||||||
|
Future<int> launch = runCommandAndStreamOutput(launchCommand, trace: true);
|
||||||
|
|
||||||
|
List<int> ports = await launch.then((int result) async {
|
||||||
|
installationResult = result;
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
printTrace("Failed to launch the application on device.");
|
||||||
|
return <int>[null, null];
|
||||||
|
}
|
||||||
|
|
||||||
|
printTrace("Application launched on the device. Attempting to forward ports.");
|
||||||
|
|
||||||
|
return Future.wait(<Future<int>>[
|
||||||
|
_acquireAndForwardPort(ProtocolDiscovery.kObservatoryService, debuggingOptions.observatoryPort),
|
||||||
|
_acquireAndForwardPort(ProtocolDiscovery.kDiagnosticService, debuggingOptions.diagnosticPort),
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
printTrace("Local Observatory Port: ${ports[0]}");
|
||||||
|
printTrace("Local Diagnostic Server Port: ${ports[1]}");
|
||||||
|
|
||||||
|
localObsPort = ports[0];
|
||||||
|
localDiagPort = ports[1];
|
||||||
|
}
|
||||||
|
|
||||||
if (installationResult != 0) {
|
if (installationResult != 0) {
|
||||||
printError('Could not install ${bundle.path} on $id.');
|
printError('Could not install ${bundle.path} on $id.');
|
||||||
return new LaunchResult.failed();
|
return new LaunchResult.failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LaunchResult.succeeded();
|
return new LaunchResult.succeeded(observatoryPort: localObsPort, diagnosticPort: localDiagPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> _acquireAndForwardPort(String serviceName, int localPort) async {
|
||||||
|
Duration stepTimeout = const Duration(seconds: 10);
|
||||||
|
|
||||||
|
Future<int> remote = new ProtocolDiscovery(logReader, serviceName).nextPort();
|
||||||
|
|
||||||
|
int remotePort = await remote.timeout(stepTimeout,
|
||||||
|
onTimeout: () {
|
||||||
|
printTrace("Timeout while attempting to retrieve remote port for $serviceName");
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (remotePort == null) {
|
||||||
|
printTrace("Could not read port on device for $serviceName");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((localPort == null) || (localPort == 0)) {
|
||||||
|
localPort = await findAvailablePort();
|
||||||
|
printTrace("Auto selected local port to $localPort");
|
||||||
|
}
|
||||||
|
|
||||||
|
int forwardResult = await portForwarder.forward(remotePort,
|
||||||
|
hostPort: localPort).timeout(stepTimeout, onTimeout: () {
|
||||||
|
printTrace("Timeout while atempting to foward port for $serviceName");
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (forwardResult == null) {
|
||||||
|
printTrace("Could not foward remote $serviceName port $remotePort to local port $localPort");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
printTrace("Successfully forwarded remote $serviceName port $remotePort to $localPort.");
|
||||||
|
return localPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> restartApp(
|
||||||
|
ApplicationPackage package,
|
||||||
|
LaunchResult result, {
|
||||||
|
String mainPath,
|
||||||
|
Observatory observatory
|
||||||
|
}) async {
|
||||||
|
return observatory.isolateReload(observatory.firstIsolateId).then((Response response) {
|
||||||
|
return true;
|
||||||
|
}).catchError((dynamic error) {
|
||||||
|
printError('Error restarting app: $error');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -306,11 +420,16 @@ class _IOSDeviceLogReader extends DeviceLogReader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static final RegExp _runnerRegex = new RegExp(r'FlutterRunner');
|
// Match for lines like "Runner[297] <Notice>: " in syslog.
|
||||||
|
static final RegExp _runnerRegex = new RegExp(r'Runner\[[\d]+\] <[A-Za-z]+>: ');
|
||||||
|
|
||||||
void _onLine(String line) {
|
void _onLine(String line) {
|
||||||
if (_runnerRegex.hasMatch(line))
|
Match match = _runnerRegex.firstMatch(line);
|
||||||
_linesController.add(line);
|
|
||||||
|
if (match != null) {
|
||||||
|
// Only display the log line after the initial device and executable information.
|
||||||
|
_linesController.add(line.substring(match.end));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _stop() {
|
void _stop() {
|
||||||
@ -319,16 +438,14 @@ class _IOSDeviceLogReader extends DeviceLogReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _IOSDevicePortForwarder extends DevicePortForwarder {
|
class _IOSDevicePortForwarder extends DevicePortForwarder {
|
||||||
_IOSDevicePortForwarder(this.device);
|
_IOSDevicePortForwarder(this.device) : _forwardedPorts = new List<ForwardedPort>();
|
||||||
|
|
||||||
final IOSDevice device;
|
final IOSDevice device;
|
||||||
|
|
||||||
|
final List<ForwardedPort> _forwardedPorts;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ForwardedPort> get forwardedPorts {
|
List<ForwardedPort> get forwardedPorts => _forwardedPorts;
|
||||||
final List<ForwardedPort> ports = <ForwardedPort>[];
|
|
||||||
// TODO(chinmaygarde): Implement.
|
|
||||||
return ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> forward(int devicePort, {int hostPort: null}) async {
|
Future<int> forward(int devicePort, {int hostPort: null}) async {
|
||||||
@ -336,12 +453,42 @@ class _IOSDevicePortForwarder extends DevicePortForwarder {
|
|||||||
// Auto select host port.
|
// Auto select host port.
|
||||||
hostPort = await findAvailablePort();
|
hostPort = await findAvailablePort();
|
||||||
}
|
}
|
||||||
// TODO(chinmaygarde): Implement.
|
|
||||||
return hostPort;
|
// Usage: iproxy LOCAL_TCP_PORT DEVICE_TCP_PORT UDID
|
||||||
|
Process process = await runCommand(<String>[
|
||||||
|
device.iproxyPath,
|
||||||
|
hostPort.toString(),
|
||||||
|
devicePort.toString(),
|
||||||
|
device.id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
ForwardedPort forwardedPort = new ForwardedPort.withContext(hostPort,
|
||||||
|
devicePort, process);
|
||||||
|
|
||||||
|
printTrace("Forwarded port $forwardedPort");
|
||||||
|
|
||||||
|
_forwardedPorts.add(forwardedPort);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Null> unforward(ForwardedPort forwardedPort) async {
|
Future<Null> unforward(ForwardedPort forwardedPort) async {
|
||||||
// TODO(chinmaygarde): Implement.
|
if (!_forwardedPorts.remove(forwardedPort)) {
|
||||||
|
// Not in list. Nothing to remove.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
printTrace("Unforwarding port $forwardedPort");
|
||||||
|
|
||||||
|
Process process = forwardedPort.context;
|
||||||
|
|
||||||
|
if (process != null) {
|
||||||
|
Process.killPid(process.pid);
|
||||||
|
} else {
|
||||||
|
printError("Forwarded port did not have a valid process");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user