Skip to content

Fix connect ECONNREFUSED error when trying to debug on iOS Sim #2704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions lib/commands/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export abstract class DebugPlatformCommand implements ICommand {
constructor(private debugService: IPlatformDebugService,
private $devicesService: Mobile.IDevicesService,
private $injector: IInjector,
private $logger: ILogger,
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
private $config: IConfiguration,
private $usbLiveSyncService: ILiveSyncService,
private $debugDataService: IDebugDataService,
protected $platformService: IPlatformService,
protected $projectData: IProjectData,
protected $options: IOptions,
protected $platformsData: IPlatformsData) {
protected $platformsData: IPlatformsData,
protected $logger: ILogger) {
this.$projectData.initializeProjectData();
}

Expand All @@ -31,9 +31,7 @@ export abstract class DebugPlatformCommand implements ICommand {
teamId: this.$options.teamId
};

const buildConfig: IBuildConfig = _.merge({ buildForDevice: this.$options.forDevice }, deployOptions);

const debugData = this.$debugDataService.createDebugData(this.debugService, this.$options, buildConfig);
let debugData = this.$debugDataService.createDebugData(this.$projectData, this.$options);

await this.$platformService.trackProjectType(this.$projectData);

Expand All @@ -57,6 +55,9 @@ export abstract class DebugPlatformCommand implements ICommand {

await deviceAppData.device.applicationManager.stopApplication(applicationId);

const buildConfig: IBuildConfig = _.merge({ buildForDevice: this.$options.forDevice }, deployOptions);
debugData.pathToAppPackage = this.$platformService.lastOutputPath(this.debugService.platform, buildConfig, projectData);

this.printDebugInformation(await this.debugService.debug(debugData, debugOptions));
};

Expand All @@ -80,18 +81,18 @@ export abstract class DebugPlatformCommand implements ICommand {
return true;
}

private printDebugInformation(information: string[]): void {
protected printDebugInformation(information: string[]): void {
_.each(information, i => {
this.$logger.info(`To start debugging, open the following URL in Chrome:${EOL}${i}${EOL}`.cyan);
});
}
}

export class DebugIOSCommand extends DebugPlatformCommand {
constructor($iOSDebugService: IPlatformDebugService,
constructor(protected $logger: ILogger,
$iOSDebugService: IPlatformDebugService,
$devicesService: Mobile.IDevicesService,
$injector: IInjector,
$logger: ILogger,
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
$config: IConfiguration,
$usbLiveSyncService: ILiveSyncService,
Expand All @@ -101,22 +102,28 @@ export class DebugIOSCommand extends DebugPlatformCommand {
$projectData: IProjectData,
$platformsData: IPlatformsData,
$iosDeviceOperations: IIOSDeviceOperations) {
super($iOSDebugService, $devicesService, $injector, $logger, $devicePlatformsConstants, $config, $usbLiveSyncService, $debugDataService, $platformService, $projectData, $options, $platformsData);
super($iOSDebugService, $devicesService, $injector, $devicePlatformsConstants, $config, $usbLiveSyncService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger);
$iosDeviceOperations.setShouldDispose(this.$options.justlaunch);
}

public async canExecute(args: string[]): Promise<boolean> {
return await super.canExecute(args) && await this.$platformService.validateOptions(this.$options.provision, this.$projectData, this.$platformsData.availablePlatforms.iOS);
}

protected printDebugInformation(information: string[]): void {
if (this.$options.chrome) {
super.printDebugInformation(information);
}
}
}

$injector.registerCommand("debug|ios", DebugIOSCommand);

export class DebugAndroidCommand extends DebugPlatformCommand {
constructor($androidDebugService: IPlatformDebugService,
constructor($logger: ILogger,
$androidDebugService: IPlatformDebugService,
$devicesService: Mobile.IDevicesService,
$injector: IInjector,
$logger: ILogger,
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
$config: IConfiguration,
$usbLiveSyncService: ILiveSyncService,
Expand All @@ -125,7 +132,7 @@ export class DebugAndroidCommand extends DebugPlatformCommand {
$options: IOptions,
$projectData: IProjectData,
$platformsData: IPlatformsData) {
super($androidDebugService, $devicesService, $injector, $logger, $devicePlatformsConstants, $config, $usbLiveSyncService, $debugDataService, $platformService, $projectData, $options, $platformsData);
super($androidDebugService, $devicesService, $injector, $devicePlatformsConstants, $config, $usbLiveSyncService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger);
}

public async canExecute(args: string[]): Promise<boolean> {
Expand Down
2 changes: 1 addition & 1 deletion lib/common
2 changes: 1 addition & 1 deletion lib/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ interface IAndroidToolsInfoData {
}

interface ISocketProxyFactory extends NodeJS.EventEmitter {
createTCPSocketProxy(factory: () => Promise<any>): any;
createTCPSocketProxy(factory: () => Promise<any>): Promise<any>;
createWebSocketProxy(factory: () => Promise<any>): Promise<any>;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/definitions/debug.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
interface IDebugData {
deviceIdentifier: string;
applicationIdentifier: string;
pathToAppPackage: string;
pathToAppPackage?: string;
projectName?: string;
projectDir?: string;
}
Expand All @@ -17,7 +17,7 @@ interface IDebugOptions {
}

interface IDebugDataService {
createDebugData(debugService: IPlatformDebugService, options: IOptions, buildConfig: IBuildConfig): IDebugData;
createDebugData(projectData: IProjectData, options: IOptions): IDebugData;
}

interface IDebugService extends NodeJS.EventEmitter {
Expand Down
55 changes: 30 additions & 25 deletions lib/device-sockets/ios/socket-proxy-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CONNECTION_ERROR_EVENT_NAME } from "../../constants";
import { PacketStream } from "./packet-stream";
import * as net from "net";
import * as ws from "ws";
import * as helpers from "../../common/helpers";
import temp = require("temp");

export class SocketProxyFactory extends EventEmitter implements ISocketProxyFactory {
Expand All @@ -14,7 +15,9 @@ export class SocketProxyFactory extends EventEmitter implements ISocketProxyFact
super();
}

public createTCPSocketProxy(factory: () => Promise<net.Socket>): net.Server {
public async createTCPSocketProxy(factory: () => Promise<net.Socket>): Promise<net.Server> {
const socketFactory = async (callback: (_socket: net.Socket) => void) => helpers.connectEventually(factory, callback);

this.$logger.info("\nSetting up proxy...\nPress Ctrl + C to terminate, or disconnect.\n");

let server = net.createServer({
Expand All @@ -31,32 +34,34 @@ export class SocketProxyFactory extends EventEmitter implements ISocketProxyFact
}
});

const backendSocket = await factory();
this.$logger.info("Backend socket created.");

backendSocket.on("end", () => {
this.$logger.info("Backend socket closed!");
if (!(this.$config.debugLivesync && this.$options.watch)) {
process.exit(0);
}
});
await socketFactory((backendSocket: net.Socket) => {
this.$logger.info("Backend socket created.");

frontendSocket.on("close", () => {
console.log("frontend socket closed");
if (!(<any>backendSocket).destroyed) {
backendSocket.destroy();
}
backendSocket.on("end", () => {
this.$logger.info("Backend socket closed!");
if (!(this.$config.debugLivesync && this.$options.watch)) {
process.exit(0);
}
});

frontendSocket.on("close", () => {
this.$logger.info("Frontend socket closed");
if (!(<any>backendSocket).destroyed) {
backendSocket.destroy();
}
});

backendSocket.on("close", () => {
this.$logger.info("Backend socket closed");
if (!(<any>frontendSocket).destroyed) {
frontendSocket.destroy();
}
});

backendSocket.pipe(frontendSocket);
frontendSocket.pipe(backendSocket);
frontendSocket.resume();
});
backendSocket.on("close", () => {
console.log("backend socket closed");
if (!(<any>frontendSocket).destroyed) {
frontendSocket.destroy();
}
});

backendSocket.pipe(frontendSocket);
frontendSocket.pipe(backendSocket);
frontendSocket.resume();
});

let socketFileLocation = temp.path({ suffix: ".sock" });
Expand Down
6 changes: 2 additions & 4 deletions lib/services/android-debug-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ class AndroidDebugService extends DebugServiceBase implements IPlatformDebugServ
let startDebuggerCommand = ["am", "broadcast", "-a", `\"${packageName}-debug\"`, "--ez", "enable", "true"];
await this.device.adb.executeShellCommand(startDebuggerCommand);

if (debugOptions.chrome) {
let port = await this.getForwardedLocalDebugPortForPackageName(deviceId, packageName);
return `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${port}`;
}
let port = await this.getForwardedLocalDebugPortForPackageName(deviceId, packageName);
return `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${port}`;
}

private detachDebugger(packageName: string): Promise<void> {
Expand Down
37 changes: 4 additions & 33 deletions lib/services/debug-data-service.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
export class DebugDataService implements IDebugDataService {
constructor(private $projectData: IProjectData,
private $platformService: IPlatformService,
private $platformsData: IPlatformsData,
private $mobileHelper: Mobile.IMobileHelper) { }

public createDebugData(debugService: IPlatformDebugService, options: IOptions, buildConfig: IBuildConfig): IDebugData {
this.$projectData.initializeProjectData(options.path);
public createDebugData(projectData: IProjectData, options: IOptions): IDebugData {
return {
applicationIdentifier: this.$projectData.projectId,
projectDir: this.$projectData.projectDir,
applicationIdentifier: projectData.projectId,
projectDir: projectData.projectDir,
deviceIdentifier: options.device,
pathToAppPackage: this.getPathToAppPackage(debugService, options, buildConfig),
projectName: this.$projectData.projectName
projectName: projectData.projectName
};
}

private getPathToAppPackage(debugService: IPlatformDebugService, options: IOptions, buildConfig: IBuildConfig): string {
if (this.$mobileHelper.isAndroidPlatform(debugService.platform)) {
if (!options.start && !options.emulator) {
const platformData = this.getPlatformData(debugService);

return this.$platformService.getLatestApplicationPackageForDevice(platformData, buildConfig).packageName;
}
} else if (this.$mobileHelper.isiOSPlatform(debugService.platform)) {
if (options.emulator) {
const platformData = this.getPlatformData(debugService);

return this.$platformService.getLatestApplicationPackageForEmulator(platformData, buildConfig).packageName;
}
}

return null;
}

private getPlatformData(debugService: IPlatformDebugService): IPlatformData {
return this.$platformsData.getPlatformData(debugService.platform, this.$projectData);
}
}

$injector.register("debugDataService", DebugDataService);
10 changes: 8 additions & 2 deletions lib/services/ios-debug-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as log4js from "log4js";
import { ChildProcess } from "child_process";
import { DebugServiceBase } from "./debug-service-base";
import { CONNECTION_ERROR_EVENT_NAME } from "../constants";
import { getPidFromiOSSimulatorLogs } from "../common/helpers";

import byline = require("byline");

Expand Down Expand Up @@ -107,7 +108,12 @@ class IOSDebugService extends DebugServiceBase implements IPlatformDebugService
lineStream.on('data', (line: NodeBuffer) => {
let lineText = line.toString();
if (lineText && _.startsWith(lineText, debugData.applicationIdentifier)) {
let pid = _.trimStart(lineText, debugData.applicationIdentifier + ": ");
const pid = getPidFromiOSSimulatorLogs(debugData.applicationIdentifier, lineText);
if (!pid) {
this.$logger.trace(`Line ${lineText} does not contain PID of the application ${debugData.applicationIdentifier}.`);
return;
}

this._lldbProcess = this.$childProcess.spawn("lldb", ["-p", pid]);
if (log4js.levels.TRACE.isGreaterThanOrEqualTo(this.$logger.getLevel())) {
this._lldbProcess.stdout.pipe(process.stdout);
Expand Down Expand Up @@ -182,7 +188,7 @@ class IOSDebugService extends DebugServiceBase implements IPlatformDebugService
const commitSHA = "02e6bde1bbe34e43b309d4ef774b1168d25fd024"; // corresponds to 55.0.2883 Chrome version
return `chrome-devtools://devtools/remote/serve_file/@${commitSHA}/inspector.html?experiments=true&ws=localhost:${this._socketProxy.options.port}`;
} else {
this._socketProxy = this.$socketProxyFactory.createTCPSocketProxy(this.getSocketFactory(device));
this._socketProxy = await this.$socketProxyFactory.createTCPSocketProxy(this.getSocketFactory(device));
await this.openAppInspector(this._socketProxy.address(), debugData, debugOptions);
return null;
}
Expand Down
14 changes: 10 additions & 4 deletions lib/services/test-execution-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,9 @@ class TestExecutionService implements ITestExecutionService {
await this.$usbLiveSyncService.liveSync(platform, projectData);

if (this.$options.debugBrk) {
const buildConfig: IBuildConfig = _.merge({ buildForDevice: this.$options.forDevice }, deployOptions);
this.$logger.info('Starting debugger...');
let debugService: IPlatformDebugService = this.$injector.resolve(`${platform}DebugService`);
const debugData: IDebugData = this.$debugDataService.createDebugData(debugService, this.$options, buildConfig);
const debugData = this.getDebugData(platform, projectData, deployOptions);
await debugService.debugStart(debugData, this.$options);
}
resolve();
Expand Down Expand Up @@ -143,8 +142,7 @@ class TestExecutionService implements ITestExecutionService {

if (this.$options.debugBrk) {
const debugService = this.getDebugService(platform);
const buildConfig: IBuildConfig = _.merge({ buildForDevice: this.$options.forDevice }, deployOptions);
const debugData = this.$debugDataService.createDebugData(debugService, this.$options, buildConfig);
const debugData = this.getDebugData(platform, projectData, deployOptions);
await debugService.debug(debugData, this.$options);
} else {
await this.$platformService.deployPlatform(platform, appFilesUpdaterOptions, deployOptions, projectData, { provision: this.$options.provision, sdk: this.$options.sdk });
Expand Down Expand Up @@ -247,5 +245,13 @@ class TestExecutionService implements ITestExecutionService {

return karmaConfig;
}

private getDebugData(platform: string, projectData: IProjectData, deployOptions: IDeployPlatformOptions): IDebugData {
const buildConfig: IBuildConfig = _.merge({ buildForDevice: this.$options.forDevice }, deployOptions);
let debugData = this.$debugDataService.createDebugData(projectData, this.$options);
debugData.pathToAppPackage = this.$platformService.lastOutputPath(platform, buildConfig, projectData);

return debugData;
}
}
$injector.register('testExecutionService', TestExecutionService);