From d2d9d1f1b0520eb89c90202a0d5fdd504307a8d1 Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Wed, 20 Mar 2019 11:38:55 +0200 Subject: [PATCH 1/2] fix: do not wait 60 seconds for debugger port when the app is crashed --- lib/common/mobile/ios/device/ios-device.ts | 3 +- lib/common/mobile/ios/ios-device-base.ts | 10 +- .../ios/simulator/ios-simulator-device.ts | 3 +- .../ios-debugger-port-service.d.ts | 3 +- lib/services/ios-debugger-port-service.ts | 39 +++++-- test/services/ios-debugger-port-service.ts | 104 ++++++++++++------ 6 files changed, 111 insertions(+), 51 deletions(-) diff --git a/lib/common/mobile/ios/device/ios-device.ts b/lib/common/mobile/ios/device/ios-device.ts index 6abe9618ea..f51ba972a5 100644 --- a/lib/common/mobile/ios/device/ios-device.ts +++ b/lib/common/mobile/ios/device/ios-device.ts @@ -60,8 +60,7 @@ export class IOSDevice extends IOSDeviceBase { } } - protected async getDebugSocketCore(appId: string, projectName: string): Promise { - await super.attachToDebuggerFoundEvent(projectName); + protected async getDebugSocketCore(appId: string): Promise { await this.$iOSSocketRequestExecutor.executeAttachRequest(this, constants.AWAIT_NOTIFICATION_TIMEOUT_SECONDS, appId); const port = await super.getDebuggerPort(appId); const deviceId = this.deviceInfo.identifier; diff --git a/lib/common/mobile/ios/ios-device-base.ts b/lib/common/mobile/ios/ios-device-base.ts index 85ccb586ea..ee585c2b25 100644 --- a/lib/common/mobile/ios/ios-device-base.ts +++ b/lib/common/mobile/ios/ios-device-base.ts @@ -22,7 +22,9 @@ export abstract class IOSDeviceBase implements Mobile.IiOSDevice { return this.cachedSockets[appId]; } - this.cachedSockets[appId] = await this.getDebugSocketCore(appId, projectName); + await this.attachToDebuggerFoundEvent(appId, projectName); + await this.applicationManager.startApplication({ appId, projectName }); + this.cachedSockets[appId] = await this.getDebugSocketCore(appId); if (this.cachedSockets[appId]) { this.cachedSockets[appId].on("close", async () => { @@ -38,11 +40,11 @@ export abstract class IOSDeviceBase implements Mobile.IiOSDevice { ); } - protected abstract async getDebugSocketCore(appId: string, projectName: string): Promise; + protected abstract async getDebugSocketCore(appId: string): Promise; - protected async attachToDebuggerFoundEvent(projectName: string): Promise { + protected async attachToDebuggerFoundEvent(appId: string, projectName: string): Promise { await this.startDeviceLogProcess(projectName); - await this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(); + await this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(appId); } protected async getDebuggerPort(appId: string): Promise { diff --git a/lib/common/mobile/ios/simulator/ios-simulator-device.ts b/lib/common/mobile/ios/simulator/ios-simulator-device.ts index 15f2533c08..b05dde67b6 100644 --- a/lib/common/mobile/ios/simulator/ios-simulator-device.ts +++ b/lib/common/mobile/ios/simulator/ios-simulator-device.ts @@ -53,9 +53,8 @@ export class IOSSimulator extends IOSDeviceBase implements Mobile.IiOSDevice { return this.$iOSSimulatorLogProvider.startLogProcess(this.simulator.id, options); } - protected async getDebugSocketCore(appId: string, projectName: string): Promise { + protected async getDebugSocketCore(appId: string): Promise { let socket: net.Socket; - await super.attachToDebuggerFoundEvent(projectName); const attachRequestMessage = this.$iOSNotification.getAttachRequest(appId, this.deviceInfo.identifier); await this.$iOSEmulatorServices.postDarwinNotification(attachRequestMessage, this.deviceInfo.identifier); const port = await super.getDebuggerPort(appId); diff --git a/lib/definitions/ios-debugger-port-service.d.ts b/lib/definitions/ios-debugger-port-service.d.ts index 340b0c9e84..4d81347323 100644 --- a/lib/definitions/ios-debugger-port-service.d.ts +++ b/lib/definitions/ios-debugger-port-service.d.ts @@ -12,6 +12,7 @@ interface IIOSDebuggerPortData { interface IIOSDebuggerPortStoredData { port: number; timer?: NodeJS.Timer; + error?: Error; } interface IIOSDebuggerPortService { @@ -24,5 +25,5 @@ interface IIOSDebuggerPortService { * Attaches on DEBUGGER_PORT_FOUND event and stores the port * @returns {Promise} */ - attachToDebuggerPortFoundEvent(): Promise; + attachToDebuggerPortFoundEvent(appId: string): Promise; } \ No newline at end of file diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index 1f411d00c5..e0fbf4736b 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -4,33 +4,40 @@ import { APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../constants"; export class IOSDebuggerPortService implements IIOSDebuggerPortService { public static DEBUG_PORT_LOG_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/; + public static APP_CRASH_LOG_REGEX = /Fatal JavaScript exception \- application has been terminated/; private mapDebuggerPortData: IDictionary = {}; + private currentAppId: string; constructor(private $logParserService: ILogParserService, private $iOSNotification: IiOSNotification, private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, private $logger: ILogger) { } - public getPort(data: IIOSDebuggerPortInputData): Promise { - return new Promise((resolve, reject) => { + public async getPort(data: IIOSDebuggerPortInputData): Promise { + return new Promise((resolve, reject) => { const key = `${data.deviceId}${data.appId}`; const retryInterval = 500; let retryCount = Math.max(APPLICATION_RESPONSE_TIMEOUT_SECONDS * 1000 / retryInterval, 10); const interval = setInterval(() => { - let port = this.getPortByKey(key); + const port = this.getPortByKey(key); if (port || retryCount === 0) { clearInterval(interval); resolve(port); } else { - port = this.getPortByKey(key); - retryCount--; + if (this.mapDebuggerPortData[key] && this.mapDebuggerPortData[key].error) { + clearInterval(interval); + reject(this.mapDebuggerPortData[key].error); + } else { + retryCount--; + } } }, retryInterval); }); } - public async attachToDebuggerPortFoundEvent(): Promise { + public async attachToDebuggerPortFoundEvent(appId: string): Promise { + this.currentAppId = appId; this.attachToDebuggerPortFoundEventCore(); this.attachToAttachRequestEvent(); } @@ -43,6 +50,23 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { name: "debugPort", platform: this.$devicePlatformsConstants.iOS.toLowerCase() }); + this.$logParserService.addParseRule({ + regex: IOSDebuggerPortService.APP_CRASH_LOG_REGEX, + handler: this.handleAppCrash.bind(this), + name: "appCrash", + platform: this.$devicePlatformsConstants.iOS.toLowerCase() + }); + } + private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void { + const data = { + port: 0, + appId: this.currentAppId, + deviceId, + error: new Error("The application has been terminated.") + }; + + this.clearTimeout(data); + this.setData(data, { port: data.port, error: data.error }); } private handlePortFound(matches: RegExpMatchArray, deviceId: string): void { @@ -73,7 +97,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { } private getPortByKey(key: string): number { - if (this.mapDebuggerPortData[key]) { + if (this.mapDebuggerPortData[key] && this.mapDebuggerPortData[key].port) { return this.mapDebuggerPortData[key].port; } @@ -89,6 +113,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { this.mapDebuggerPortData[key].port = storedData.port; this.mapDebuggerPortData[key].timer = storedData.timer; + this.mapDebuggerPortData[key].error = storedData.error; } private clearTimeout(data: IIOSDebuggerPortData): void { diff --git a/test/services/ios-debugger-port-service.ts b/test/services/ios-debugger-port-service.ts index 9e3b0335f3..503bfeed1f 100644 --- a/test/services/ios-debugger-port-service.ts +++ b/test/services/ios-debugger-port-service.ts @@ -90,6 +90,48 @@ function getMultilineDebuggerPortMessage(port: number) { 2018-04-20 09:45:51.260951+0300 localhost nglog[17917]: NativeScript debugger has opened inspector socket on port ${port} for ${appId}.`; } +function getAppCrashMessage() { + return `***** Fatal JavaScript exception - application has been terminated. *****`; +} + +function getMultilineAppCrashMessage() { + return `Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : ***** Fatal JavaScript exception - application has been terminated. ***** + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : Native stack trace: + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 1 0x1013ef370 NativeScript::reportFatalErrorBeforeShutdown(JSC::ExecState*, JSC::Exception*, bool) + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 2 0x10141fdec NativeScript::FFICallback::ffiClosureCallback(ffi_cif*, void*, void**, void*) + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 3 0x101e84494 ffi_closure_SYSV_inner + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 4 0x101e881b4 .Ldo_closure + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 5 0x183760c3c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 6 0x1837601b8 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 7 0x18375ff14 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 8 0x1837dd84c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 9 0x183696f38 _CFXNotificationPost + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 10 0x184107bbc + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 11 0x18d3da2f0 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 12 0x18d3a75e0 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 13 0x18d9d7b1c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 14 0x18d3a6dd0 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 15 0x18d3a6c6c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 16 0x18d3a5afc + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 17 0x18e03b84c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 18 0x18d3a51ec + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 19 0x18de20ac8 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 20 0x18df6ebf8 _performActionsWithDelayForTransitionContext + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 21 0x18d3a4c0c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 22 0x18d3a45a8 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 23 0x18d3a15e0 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 24 0x18d3a1330 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 25 0x185fcf470 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 26 0x185fd7d6c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 27 0x1830c0a60 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 28 0x1830c8170 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 29 0x186003878 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 30 0x18600351c + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 31 0x186003ab8 + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : JavaScript stack trace: + Mar 20 15:13:23 iOS-Team-iPad-2-Mini-Black hwJs(NativeScript)[3946] : 1 @file:///app/vendor.js:12552:56`; +} + describe("iOSDebuggerPortService", () => { let injector: IInjector, iOSDebuggerPortService: IIOSDebuggerPortService, deviceLogProvider: Mobile.IDeviceLogProvider; let clock: sinon.SinonFakeTimers = null; @@ -108,71 +150,63 @@ describe("iOSDebuggerPortService", () => { function emitDeviceLog(message: string) { deviceLogProvider.emit(DEVICE_LOG_EVENT_NAME, message, device.deviceInfo.identifier); } - - function emitStartingIOSApplicationEvent() { - device.applicationManager.emit("STARTING_IOS_APPLICATION", { - appId: appId, - deviceId: device.deviceInfo.identifier - }); - } - describe("getPort", () => { - const testCases = [ + const testCases: { name: string, emittedPort?: number, crashApp?: boolean, expectedError?: string }[] = [ { name: `should return null when ${DEBUGGER_PORT_FOUND_EVENT_NAME} event is not emitted`, - emittedPort: null, - emitStartingIOSApplicationEvent: false + emittedPort: null }, { name: `should return default port when ${DEBUGGER_PORT_FOUND_EVENT_NAME} event is emitted`, - emittedPort: 18181, - emitStartingIOSApplicationEvent: false + emittedPort: 18181 }, { name: `should return random port when ${DEBUGGER_PORT_FOUND_EVENT_NAME} event is emitted`, - emittedPort: 65432, - emitStartingIOSApplicationEvent: false - }, - { - name: `should return default port when ${DEBUGGER_PORT_FOUND_EVENT_NAME} and STARTING_IOS_APPLICATION events are emitted`, - emittedPort: 18181, - emitStartingIOSApplicationEvent: true + emittedPort: 65432 }, { - name: `should return random port when ${DEBUGGER_PORT_FOUND_EVENT_NAME} and STARTING_IOS_APPLICATION events are emitted`, - emittedPort: 12345, - emitStartingIOSApplicationEvent: true + name: `should reject when the app crashes`, + expectedError: "The application has been terminated.", + crashApp: true } ]; _.each(testCases, testCase => { it(testCase.name, async () => { - await iOSDebuggerPortService.attachToDebuggerPortFoundEvent(); - if (testCase.emitStartingIOSApplicationEvent) { - emitStartingIOSApplicationEvent(); - } + await iOSDebuggerPortService.attachToDebuggerPortFoundEvent(appId); if (testCase.emittedPort) { emitDeviceLog(getDebuggerPortMessage(testCase.emittedPort)); + } else if (testCase.crashApp) { + emitDeviceLog(getAppCrashMessage()); } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); clock.tick(70000); - const port = await promise; - assert.deepEqual(port, testCase.emittedPort); + let port = 0; + try { + port = await promise; + assert.deepEqual(port, testCase.emittedPort); + } catch (err) { + assert.deepEqual(err.message, testCase.expectedError); + } }); it(`${testCase.name} for multiline debugger port message.`, async () => { - await iOSDebuggerPortService.attachToDebuggerPortFoundEvent(); - if (testCase.emitStartingIOSApplicationEvent) { - emitStartingIOSApplicationEvent(); - } + await iOSDebuggerPortService.attachToDebuggerPortFoundEvent(appId); if (testCase.emittedPort) { emitDeviceLog(getMultilineDebuggerPortMessage(testCase.emittedPort)); + } else if (testCase.crashApp) { + emitDeviceLog(getMultilineAppCrashMessage()); } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); clock.tick(70000); - const port = await promise; - assert.deepEqual(port, testCase.emittedPort); + let port = 0; + try { + port = await promise; + assert.deepEqual(port, testCase.emittedPort); + } catch (err) { + assert.deepEqual(err.message, testCase.expectedError); + } }); }); }); From 41ae6720b50f10ef6277a07b14809393c28931a6 Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Thu, 21 Mar 2019 11:02:22 +0200 Subject: [PATCH 2/2] fix: handle app crashes the same as hmr sync failures in order to allow app recovery --- lib/common/constants.ts | 1 + lib/definitions/hmr-status-service.d.ts | 1 + lib/services/hmr-status-service.ts | 30 +++++++++++++++++++---- lib/services/ios-debugger-port-service.ts | 6 ++--- lib/services/livesync/livesync-service.ts | 9 +++++-- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/lib/common/constants.ts b/lib/common/constants.ts index c208f88cf5..285a33df5d 100644 --- a/lib/common/constants.ts +++ b/lib/common/constants.ts @@ -54,6 +54,7 @@ export class EmulatorDiscoveryNames { export const DEVICE_LOG_EVENT_NAME = "deviceLogData"; export const IOS_LOG_PREDICATE = 'senderImagePath contains "NativeScript" || eventMessage contains[c] "NativeScript"'; +export const IOS_APP_CRASH_LOG_REG_EXP = /Fatal JavaScript exception \- application has been terminated/; export const TARGET_FRAMEWORK_IDENTIFIERS = { Cordova: "Cordova", diff --git a/lib/definitions/hmr-status-service.d.ts b/lib/definitions/hmr-status-service.d.ts index 2af5f4c3d7..3d2f2ab6f2 100644 --- a/lib/definitions/hmr-status-service.d.ts +++ b/lib/definitions/hmr-status-service.d.ts @@ -1,4 +1,5 @@ interface IHmrStatusService { + watchHmrStatus(deviceId: string, operationHash: string): void; getHmrStatus(deviceId: string, operationHash: string): Promise; attachToHmrStatusEvent(): void; } \ No newline at end of file diff --git a/lib/services/hmr-status-service.ts b/lib/services/hmr-status-service.ts index 2c3241c2c1..60e65b9fbc 100644 --- a/lib/services/hmr-status-service.ts +++ b/lib/services/hmr-status-service.ts @@ -1,5 +1,5 @@ import { cache } from "../common/decorators"; -import { HmrConstants } from "../common/constants"; +import { HmrConstants, IOS_APP_CRASH_LOG_REG_EXP } from "../common/constants"; export class HmrStatusService implements IHmrStatusService { public static HMR_STATUS_LOG_REGEX = /([a-z A-Z]*) hmr hash ([a-z0-9]*)\./; @@ -11,9 +11,10 @@ export class HmrStatusService implements IHmrStatusService { constructor(private $logParserService: ILogParserService, private $processService: IProcessService, + private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, private $logger: ILogger) { - this.$processService.attachToProcessExitSignals(this, this.dispose); - } + this.$processService.attachToProcessExitSignals(this, this.dispose); + } public getHmrStatus(deviceId: string, operationHash: string): Promise { return new Promise((resolve, reject) => { @@ -33,6 +34,10 @@ export class HmrStatusService implements IHmrStatusService { }); } + public watchHmrStatus(deviceId: string, operationHash: string): void { + this.setData(deviceId, operationHash); + } + @cache() public attachToHmrStatusEvent(): void { this.$logParserService.addParseRule({ @@ -40,6 +45,21 @@ export class HmrStatusService implements IHmrStatusService { handler: this.handleHmrStatusFound.bind(this), name: "hmrStatus" }); + this.$logParserService.addParseRule({ + regex: IOS_APP_CRASH_LOG_REG_EXP, + handler: this.handleAppCrash.bind(this), + name: "appCrashHmr", + platform: this.$devicePlatformsConstants.iOS.toLowerCase() + }); + } + + private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void { + for (const operationId in this.hashOperationStatuses) { + const operation = this.hashOperationStatuses[operationId]; + if (operationId.startsWith(deviceId) && !operation.status) { + operation.status = HmrConstants.HMR_ERROR_STATUS; + } + } } private handleHmrStatusFound(matches: RegExpMatchArray, deviceId: string): void { @@ -65,7 +85,7 @@ export class HmrStatusService implements IHmrStatusService { this.$logger.trace("Found hmr status.", { status, hash }); if (status) { - this.setData(status, hash, deviceId); + this.setData(deviceId, hash, status); } } @@ -77,7 +97,7 @@ export class HmrStatusService implements IHmrStatusService { return null; } - private setData(status: Number, operationHash: string, deviceId: string): void { + private setData(deviceId: string, operationHash: string, status?: Number): void { const key = `${deviceId}${operationHash}`; if (!this.hashOperationStatuses[key]) { diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index e0fbf4736b..a50cd5e10c 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -1,10 +1,9 @@ -import { DEBUGGER_PORT_FOUND_EVENT_NAME, ATTACH_REQUEST_EVENT_NAME } from "../common/constants"; +import { DEBUGGER_PORT_FOUND_EVENT_NAME, ATTACH_REQUEST_EVENT_NAME, IOS_APP_CRASH_LOG_REG_EXP } from "../common/constants"; import { cache } from "../common/decorators"; import { APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../constants"; export class IOSDebuggerPortService implements IIOSDebuggerPortService { public static DEBUG_PORT_LOG_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/; - public static APP_CRASH_LOG_REGEX = /Fatal JavaScript exception \- application has been terminated/; private mapDebuggerPortData: IDictionary = {}; private currentAppId: string; @@ -51,12 +50,13 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { platform: this.$devicePlatformsConstants.iOS.toLowerCase() }); this.$logParserService.addParseRule({ - regex: IOSDebuggerPortService.APP_CRASH_LOG_REGEX, + regex: IOS_APP_CRASH_LOG_REG_EXP, handler: this.handleAppCrash.bind(this), name: "appCrash", platform: this.$devicePlatformsConstants.iOS.toLowerCase() }); } + private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void { const data = { port: 0, diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index f00cb979bd..d150d1b417 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -664,12 +664,17 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi const service = this.getLiveSyncService(device.deviceInfo.platform); const watchAction = async (watchInfo: ILiveSyncWatchInfo): Promise => { + const isInHMRMode = liveSyncData.useHotModuleReload && platformHmrData.hash; + if (isInHMRMode) { + this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, platformHmrData.hash); + } + let liveSyncResultInfo = await service.liveSyncWatchAction(device, watchInfo); await this.refreshApplication(projectData, liveSyncResultInfo, deviceBuildInfoDescriptor.debugOptions, deviceBuildInfoDescriptor.outputPath); - // If didRecover is true, this means we were in ErrorActivity and fallback files were already transfered and app will be restarted. - if (!liveSyncResultInfo.didRecover && liveSyncData.useHotModuleReload && platformHmrData.hash) { + // If didRecover is true, this means we were in ErrorActivity and fallback files were already transferred and app will be restarted. + if (!liveSyncResultInfo.didRecover && isInHMRMode) { const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, platformHmrData.hash); if (status === HmrConstants.HMR_ERROR_STATUS) { watchInfo.filesToSync = platformHmrData.fallbackFiles;