Skip to content

Commit 58ab789

Browse files
committed
fix: enable debug-brk on real iOS devices and do not make an additional restart in the debug services
1 parent 6f646a9 commit 58ab789

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1140
-1862
lines changed

lib/commands/debug.ts

+5-59
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import { CONNECTED_STATUS } from "../common/constants";
2-
import { isInteractive } from "../common/helpers";
31
import { cache } from "../common/decorators";
4-
import { DebugCommandErrors } from "../constants";
52
import { ValidatePlatformCommandBase } from "./command-base";
63
import { LiveSyncCommandHelper } from "../helpers/livesync-command-helper";
74
import { performanceLog } from "../common/decorators";
@@ -21,7 +18,6 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements
2118
protected $errors: IErrors,
2219
private $debugDataService: IDebugDataService,
2320
private $liveSyncService: IDebugLiveSyncService,
24-
private $prompter: IPrompter,
2521
private $liveSyncCommandHelper: ILiveSyncCommandHelper,
2622
private $androidBundleValidatorHelper: IAndroidBundleValidatorHelper) {
2723
super($options, $platformsData, $platformService, $projectData);
@@ -37,7 +33,11 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements
3733

3834
const debugOptions = <IDebugOptions>_.cloneDeep(this.$options.argv);
3935

40-
const selectedDeviceForDebug = await this.getDeviceForDebug();
36+
const selectedDeviceForDebug = await this.$devicesService.pickSingleDevice({
37+
onlyEmulators: this.$options.emulator,
38+
onlyDevices: this.$options.forDevice,
39+
deviceId: this.$options.device
40+
});
4141

4242
const debugData = this.$debugDataService.createDebugData(this.$projectData, { device: selectedDeviceForDebug.deviceInfo.identifier });
4343

@@ -57,60 +57,6 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements
5757
}
5858

5959
@performanceLog()
60-
public async getDeviceForDebug(): Promise<Mobile.IDevice> {
61-
if (this.$options.forDevice && this.$options.emulator) {
62-
this.$errors.fail(DebugCommandErrors.UNABLE_TO_USE_FOR_DEVICE_AND_EMULATOR);
63-
}
64-
65-
if (this.$options.device) {
66-
const device = await this.$devicesService.getDevice(this.$options.device);
67-
return device;
68-
}
69-
70-
// Now let's take data for each device:
71-
const availableDevicesAndEmulators = this.$devicesService.getDeviceInstances()
72-
.filter(d => d.deviceInfo.status === CONNECTED_STATUS && (!this.platform || d.deviceInfo.platform.toLowerCase() === this.platform.toLowerCase()));
73-
74-
const selectedDevices = availableDevicesAndEmulators.filter(d => this.$options.emulator ? d.isEmulator : (this.$options.forDevice ? !d.isEmulator : true));
75-
76-
if (selectedDevices.length > 1) {
77-
if (isInteractive()) {
78-
const choices = selectedDevices.map(e => `${e.deviceInfo.identifier} - ${e.deviceInfo.displayName}`);
79-
80-
const selectedDeviceString = await this.$prompter.promptForChoice("Select device for debugging", choices);
81-
82-
const selectedDevice = _.find(selectedDevices, d => `${d.deviceInfo.identifier} - ${d.deviceInfo.displayName}` === selectedDeviceString);
83-
return selectedDevice;
84-
} else {
85-
const sortedInstances = _.sortBy(selectedDevices, e => e.deviceInfo.version);
86-
const emulators = sortedInstances.filter(e => e.isEmulator);
87-
const devices = sortedInstances.filter(d => !d.isEmulator);
88-
let selectedInstance: Mobile.IDevice;
89-
90-
if (this.$options.emulator || this.$options.forDevice) {
91-
// When --emulator or --forDevice is passed, the instances are already filtered
92-
// So we are sure we have exactly the type we need and we can safely return the last one (highest OS version).
93-
selectedInstance = _.last(sortedInstances);
94-
} else {
95-
if (emulators.length) {
96-
selectedInstance = _.last(emulators);
97-
} else {
98-
selectedInstance = _.last(devices);
99-
}
100-
}
101-
102-
this.$logger.warn(`Multiple devices/emulators found. Starting debugger on ${selectedInstance.deviceInfo.identifier}. ` +
103-
"If you want to debug on specific device/emulator, you can specify it with --device option.");
104-
105-
return selectedInstance;
106-
}
107-
} else if (selectedDevices.length === 1) {
108-
return _.head(selectedDevices);
109-
}
110-
111-
this.$errors.failWithoutHelp(DebugCommandErrors.NO_DEVICES_EMULATORS_FOUND_FOR_OPTIONS);
112-
}
113-
11460
public async canExecute(args: string[]): Promise<ICanExecuteCommandOutput> {
11561
this.$androidBundleValidatorHelper.validateNoAab();
11662

lib/commands/test.ts

-19
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,5 @@
11
import * as helpers from "../common/helpers";
22

3-
function RunTestCommandFactory(platform: string) {
4-
return function RunTestCommand(
5-
$options: IOptions,
6-
$testExecutionService: ITestExecutionService,
7-
$projectData: IProjectData,
8-
$analyticsService: IAnalyticsService,
9-
$platformEnvironmentRequirements: IPlatformEnvironmentRequirements) {
10-
$projectData.initializeProjectData();
11-
$analyticsService.setShouldDispose($options.justlaunch || !$options.watch);
12-
const projectFilesConfig = helpers.getProjectFilesConfig({ isReleaseBuild: $options.release });
13-
this.execute = (args: string[]): Promise<void> => $testExecutionService.startTestRunner(platform, $projectData, projectFilesConfig);
14-
this.canExecute = (args: string[]): Promise<boolean> => canExecute({ $platformEnvironmentRequirements, $projectData, $options, platform });
15-
this.allowedParameters = [];
16-
};
17-
}
18-
19-
$injector.registerCommand("dev-test|android", RunTestCommandFactory('android'));
20-
$injector.registerCommand("dev-test|ios", RunTestCommandFactory('iOS'));
21-
223
function RunKarmaTestCommandFactory(platform: string) {
234
return function RunKarmaTestCommand($options: IOptions, $testExecutionService: ITestExecutionService, $projectData: IProjectData, $analyticsService: IAnalyticsService, $platformEnvironmentRequirements: IPlatformEnvironmentRequirements) {
245
$projectData.initializeProjectData();

lib/common/appbuilder/services/livesync/ios-livesync-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class IOSLiveSyncService implements IDeviceLiveSyncService {
5151
this.$logger.trace(`Transferring from ${sourcePath} to ${destinationPath}`);
5252
shell.cp("-Rf", path.join(sourcePath, "*"), destinationPath);
5353

54-
await this.device.applicationManager.restartApplication({ appId: deviceAppData.appIdentifier, projectName: "" });
54+
await this.device.applicationManager.restartApplication({ appId: deviceAppData.appIdentifier, projectName: "", waitForDebugger: false, enableDebugging: false });
5555
} else {
5656
await this.device.fileSystem.deleteFile("/Documents/AppBuilder/ServerInfo.plist", deviceAppData.appIdentifier);
5757
const notification = this.$project.projectData.Framework === constants.TARGET_FRAMEWORK_IDENTIFIERS.NativeScript ? "com.telerik.app.refreshApp" : "com.telerik.app.refreshWebView";

lib/common/commands/device/run-application.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class RunApplicationOnDeviceCommand implements ICommand {
1515
this.$errors.failWithoutHelp("More than one device found. Specify device explicitly with --device option. To discover device ID, use $%s device command.", this.$staticConfig.CLIENT_NAME.toLowerCase());
1616
}
1717

18-
await this.$devicesService.execute(async (device: Mobile.IDevice) => await device.applicationManager.startApplication({ appId: args[0], projectName: args[1] }));
18+
await this.$devicesService.execute(async (device: Mobile.IDevice) => await device.applicationManager.startApplication({ appId: args[0], projectName: args[1], waitForDebugger: false, enableDebugging: false }));
1919
}
2020
}
2121

lib/common/definitions/mobile.d.ts

+35-27
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,8 @@ declare module Mobile {
111111
}
112112

113113
interface IiOSDevice extends IDevice {
114-
getLiveSyncSocket(appId: string): Promise<any>;
115-
destroyLiveSyncSocket(appId: string): void;
116-
117-
getDebugSocket(appId: string): Promise<any>;
114+
getDebugSocket(appId: string, projectName: string): Promise<any>;
118115
destroyDebugSocket(appId: string): void;
119-
120116
openDeviceLogStream(options?: IiOSLogStreamOptions): Promise<void>;
121117
destroyAllSockets(): void;
122118
}
@@ -221,12 +217,6 @@ declare module Mobile {
221217
* @param {string} projectName The project name of the currently running application for which we need the logs.
222218
*/
223219
setProjectNameForDevice(deviceIdentifier: string, projectName: string): void;
224-
225-
/**
226-
* Disables logs on the specified device and does not print any logs on the console.
227-
* @param {string} deviceIdentifier The unique identifier of the device.
228-
*/
229-
muteLogsForDevice(deviceIdentifier: string): void;
230220
}
231221

232222
/**
@@ -248,10 +238,6 @@ declare module Mobile {
248238
*/
249239
projectName?: string;
250240

251-
/**
252-
* Specifies if the logs will be printed on the console.
253-
*/
254-
muteLogs?: boolean;
255241
}
256242

257243
/**
@@ -311,19 +297,28 @@ declare module Mobile {
311297
justLaunch?: boolean;
312298
}
313299

300+
interface IStartApplicationData extends IApplicationData {
301+
waitForDebugger: boolean;
302+
enableDebugging: boolean;
303+
}
304+
314305
interface IInstallAppData extends IApplicationData {
315306
packagePath: string;
316307
}
317308

309+
interface IRunningAppInfo {
310+
pid: string;
311+
}
312+
318313
interface IDeviceApplicationManager extends NodeJS.EventEmitter {
319314
getInstalledApplications(): Promise<string[]>;
320315
isApplicationInstalled(appIdentifier: string): Promise<boolean>;
321316
installApplication(packageFilePath: string, appIdentifier?: string): Promise<void>;
322317
uninstallApplication(appIdentifier: string): Promise<void>;
323318
reinstallApplication(appIdentifier: string, packageFilePath: string): Promise<void>;
324-
startApplication(appData: IApplicationData): Promise<void>;
319+
startApplication(appData: IStartApplicationData): Promise<IRunningAppInfo>;
325320
stopApplication(appData: IApplicationData): Promise<void>;
326-
restartApplication(appData: IApplicationData): Promise<void>;
321+
restartApplication(appData: IStartApplicationData): Promise<IRunningAppInfo>;
327322
checkForApplicationUpdates(): Promise<void>;
328323
isLiveSyncSupported(appIdentifier: string): Promise<boolean>;
329324
getApplicationInfo(applicationIdentifier: string): Promise<Mobile.IApplicationInfo>;
@@ -550,6 +545,27 @@ declare module Mobile {
550545
* @returns {Promise<string[]>} - Returns array of errors.
551546
*/
552547
startEmulator(options?: IStartEmulatorOptions): Promise<string[]>;
548+
549+
/**
550+
* Returns a single device based on the specified options. If more than one devices are matching,
551+
* prompts the user for a manual choice or returns the first one for non interactive terminals.
552+
*/
553+
pickSingleDevice(options: IPickSingleDeviceOptions): Promise<Mobile.IDevice>
554+
}
555+
556+
interface IPickSingleDeviceOptions {
557+
/**
558+
* Pick from the connected emulators only
559+
*/
560+
onlyEmulators: boolean;
561+
/**
562+
* Pick from the connected real devices only
563+
*/
564+
onlyDevices: boolean;
565+
/**
566+
* Pick a specific device
567+
*/
568+
deviceId: string;
553569
}
554570

555571
interface IListEmulatorsOptions {
@@ -941,14 +957,6 @@ declare module Mobile {
941957
* @returns {net.Socket} Returns instance of net.Socket when connection is successful, otherwise undefined is returned.
942958
*/
943959
connectToPort(connectToPortData: IConnectToPortData): Promise<any>;
944-
945-
/**
946-
* Runs an application on emulator
947-
* @param app The path to executable .app
948-
* @param emulatorOptions Emulator options that can be passed
949-
* @returns {Promise<any>} Returns the appId with the process of the running application on the simulator. For example: org.nativescript.myapp 55434
950-
*/
951-
runApplicationOnEmulator(app: string, emulatorOptions?: IRunApplicationOnEmulatorOptions): Promise<any>;
952960
}
953961

954962
interface IEmulatorSettingsService {
@@ -1251,9 +1259,9 @@ interface IIOSDeviceOperations extends IDisposable, NodeJS.EventEmitter {
12511259

12521260
deleteFiles(deleteArray: IOSDeviceLib.IDeleteFileData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
12531261

1254-
start(startArray: IOSDeviceLib.IDdiApplicationData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
1262+
start(startArray: IOSDeviceLib.IIOSApplicationData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
12551263

1256-
stop(stopArray: IOSDeviceLib.IDdiApplicationData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
1264+
stop(stopArray: IOSDeviceLib.IIOSApplicationData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
12571265

12581266
postNotification(postNotificationArray: IOSDeviceLib.IPostNotificationData[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
12591267

lib/common/mobile/android/android-application-manager.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,15 @@ export class AndroidApplicationManager extends ApplicationManagerBase {
4747
return this.adb.executeShellCommand(["pm", "uninstall", `${appIdentifier}`], { treatErrorsAsWarnings: true });
4848
}
4949

50-
public async startApplication(appData: Mobile.IApplicationData): Promise<void> {
50+
public async startApplication(appData: Mobile.IStartApplicationData): Promise<Mobile.IRunningAppInfo> {
51+
if (appData.waitForDebugger) {
52+
await this.adb.executeShellCommand([`cat /dev/null > ${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugbreak`]);
53+
}
54+
55+
if (appData.enableDebugging) {
56+
await this.adb.executeShellCommand([`cat /dev/null > ${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugger-started`]);
57+
}
58+
5159
/*
5260
Example "pm dump <app_identifier> | grep -A 1 MAIN" output"
5361
android.intent.action.MAIN:
@@ -74,9 +82,9 @@ export class AndroidApplicationManager extends ApplicationManagerBase {
7482
await this.adb.executeShellCommand(["monkey", "-p", appIdentifier, "-c", "android.intent.category.LAUNCHER", "1"]);
7583
}
7684

85+
const deviceIdentifier = this.identifier;
86+
const processIdentifier = await this.getAppProcessId(deviceIdentifier, appIdentifier);
7787
if (!this.$options.justlaunch && !appData.justLaunch) {
78-
const deviceIdentifier = this.identifier;
79-
const processIdentifier = await this.getAppProcessId(deviceIdentifier, appIdentifier);
8088
if (processIdentifier) {
8189
this.$deviceLogProvider.setApplicationPidForDevice(deviceIdentifier, processIdentifier);
8290
await this.$logcatHelper.start({
@@ -88,6 +96,10 @@ export class AndroidApplicationManager extends ApplicationManagerBase {
8896
this.$errors.failWithoutHelp(`Unable to find running "${appIdentifier}" application on device "${deviceIdentifier}".`);
8997
}
9098
}
99+
100+
return {
101+
pid: processIdentifier
102+
};
91103
}
92104

93105
private async getAppProcessId(deviceIdentifier: string, appIdentifier: string) {

lib/common/mobile/application-manager-base.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ export abstract class ApplicationManagerBase extends EventEmitter implements Mob
2121
await this.installApplication(packageFilePath, appIdentifier);
2222
}
2323

24-
public async restartApplication(appData: Mobile.IApplicationData): Promise<void> {
24+
public async restartApplication(appData: Mobile.IApplicationData): Promise<Mobile.IRunningAppInfo> {
2525
await this.stopApplication(appData);
26-
await this.startApplication(appData);
26+
const appInfo = await this.startApplication(appData);
27+
return appInfo;
2728
}
2829

2930
public async isApplicationInstalled(appIdentifier: string): Promise<boolean> {
@@ -80,7 +81,7 @@ export abstract class ApplicationManagerBase extends EventEmitter implements Mob
8081

8182
public abstract async installApplication(packageFilePath: string, appIdentifier?: string): Promise<void>;
8283
public abstract async uninstallApplication(appIdentifier: string): Promise<void>;
83-
public abstract async startApplication(appData: Mobile.IApplicationData): Promise<void>;
84+
public abstract async startApplication(appData: Mobile.IApplicationData): Promise<Mobile.IRunningAppInfo>;
8485
public abstract async stopApplication(appData: Mobile.IApplicationData): Promise<void>;
8586
public abstract async getInstalledApplications(): Promise<string[]>;
8687
public abstract async getApplicationInfo(applicationIdentifier: string): Promise<Mobile.IApplicationInfo>;

lib/common/mobile/device-log-provider-base.ts

-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ export abstract class DeviceLogProviderBase extends EventEmitter implements Mobi
2626
this.setLogLevel(logLevel, deviceIdentifier);
2727
}
2828

29-
public muteLogsForDevice(deviceIdentifier: string): void {
30-
this.setDeviceLogOptionsProperty(deviceIdentifier, (deviceLogOptions: Mobile.IDeviceLogOptions) => deviceLogOptions.muteLogs, true);
31-
}
32-
3329
protected getApplicationPidForDevice(deviceIdentifier: string): string {
3430
return this.devicesLogOptions[deviceIdentifier] && this.devicesLogOptions[deviceIdentifier].applicationPid;
3531
}

lib/common/mobile/device-log-provider.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class DeviceLogProvider extends DeviceLogProviderBase {
1111
const loggingOptions = this.getDeviceLogOptionsForDevice(deviceIdentifier);
1212
const data = this.$logFilter.filterData(platform, lineText, loggingOptions);
1313
if (data) {
14-
this.logDataCore(data, loggingOptions);
14+
this.logDataCore(data);
1515
this.emit(DEVICE_LOG_EVENT_NAME, lineText, deviceIdentifier, platform);
1616
}
1717
}
@@ -20,10 +20,8 @@ export class DeviceLogProvider extends DeviceLogProviderBase {
2020
this.$logFilter.loggingLevel = logLevel.toUpperCase();
2121
}
2222

23-
private logDataCore(data: string, loggingOptions: Mobile.IDeviceLogOptions): void {
24-
if (!loggingOptions || (loggingOptions && !loggingOptions.muteLogs)) {
25-
this.$logger.write(data);
26-
}
23+
private logDataCore(data: string): void {
24+
this.$logger.write(data);
2725
}
2826
}
2927
$injector.register("deviceLogProvider", DeviceLogProvider);

0 commit comments

Comments
 (0)