Skip to content

Add VS device id #213231

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 1 commit into from
May 22, 2024
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.1.0",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.4",
"@vscode/proxy-agent": "^0.19.0",
Expand Down
11 changes: 11 additions & 0 deletions src/vs/base/node/id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,14 @@ export async function getSqmMachineId(errorLogger: (error: any) => void): Promis
}
return '';
}

export async function getVSDeviceId(errorLogger: (error: any) => void): Promise<string> {
try {
const deviceIdPackage = await import('@vscode/deviceid');
const id = await deviceIdPackage.getDeviceId();
return id;
} catch (err) {
errorLogger(err);
return '';
}
}
9 changes: 8 additions & 1 deletion src/vs/base/test/node/id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import { getMachineId, getSqmMachineId } from 'vs/base/node/id';
import { getMachineId, getSqmMachineId, getVSDeviceId } from 'vs/base/node/id';
import { getMac } from 'vs/base/node/macAddress';
import { flakySuite } from 'vs/base/test/node/testUtils';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
Expand All @@ -26,6 +26,13 @@ flakySuite('ID', () => {
assert.strictEqual(errors.length, 0);
});

test('getVSDeviceId', async function () {
const errors = [];
const id = await getVSDeviceId(err => errors.push(err));
assert.ok(typeof id === 'string');
assert.strictEqual(errors.length, 0);
});

test('getMac', async () => {
const macAddress = getMac();
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`);
Expand Down
21 changes: 11 additions & 10 deletions src/vs/code/electron-main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/e
import { UserDataProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataProfilesHandler';
import { ProfileStorageChangesListenerChannel } from 'vs/platform/userDataProfile/electron-main/userDataProfileStorageIpc';
import { Promises, RunOnceScheduler, runWhenGlobalIdle } from 'vs/base/common/async';
import { resolveMachineId, resolveSqmId } from 'vs/platform/telemetry/electron-main/telemetryUtils';
import { resolveMachineId, resolveSqmId, resolveVSDeviceId } from 'vs/platform/telemetry/electron-main/telemetryUtils';
import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService';
import { LoggerChannel } from 'vs/platform/log/electron-main/logIpc';
import { ILoggerMainService } from 'vs/platform/log/electron-main/loggerService';
Expand Down Expand Up @@ -611,17 +611,18 @@ export class CodeApplication extends Disposable {

// Resolve unique machine ID
this.logService.trace('Resolving machine identifier...');
const [machineId, sqmId] = await Promise.all([
const [machineId, sqmId, vsDeviceId] = await Promise.all([
resolveMachineId(this.stateService, this.logService),
resolveSqmId(this.stateService, this.logService)
resolveSqmId(this.stateService, this.logService),
resolveVSDeviceId(this.stateService, this.logService)
]);
this.logService.trace(`Resolved machine identifier: ${machineId}`);

// Shared process
const { sharedProcessReady, sharedProcessClient } = this.setupSharedProcess(machineId, sqmId);
const { sharedProcessReady, sharedProcessClient } = this.setupSharedProcess(machineId, sqmId, vsDeviceId);

// Services
const appInstantiationService = await this.initServices(machineId, sqmId, sharedProcessReady);
const appInstantiationService = await this.initServices(machineId, sqmId, vsDeviceId, sharedProcessReady);

// Auth Handler
this._register(appInstantiationService.createInstance(ProxyAuthHandler));
Expand Down Expand Up @@ -986,8 +987,8 @@ export class CodeApplication extends Disposable {
return false;
}

private setupSharedProcess(machineId: string, sqmId: string): { sharedProcessReady: Promise<MessagePortClient>; sharedProcessClient: Promise<MessagePortClient> } {
const sharedProcess = this._register(this.mainInstantiationService.createInstance(SharedProcess, machineId, sqmId));
private setupSharedProcess(machineId: string, sqmId: string, vsDeviceId: string): { sharedProcessReady: Promise<MessagePortClient>; sharedProcessClient: Promise<MessagePortClient> } {
const sharedProcess = this._register(this.mainInstantiationService.createInstance(SharedProcess, machineId, sqmId, vsDeviceId));

this._register(sharedProcess.onDidCrash(() => this.windowsMainService?.sendToFocused('vscode:reportSharedProcessCrash')));

Expand All @@ -1010,7 +1011,7 @@ export class CodeApplication extends Disposable {
return { sharedProcessReady, sharedProcessClient };
}

private async initServices(machineId: string, sqmId: string, sharedProcessReady: Promise<MessagePortClient>): Promise<IInstantiationService> {
private async initServices(machineId: string, sqmId: string, vsDeviceId: string, sharedProcessReady: Promise<MessagePortClient>): Promise<IInstantiationService> {
const services = new ServiceCollection();

// Update
Expand All @@ -1033,7 +1034,7 @@ export class CodeApplication extends Disposable {
}

// Windows
services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, sqmId, this.userEnv], false));
services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, sqmId, vsDeviceId, this.userEnv], false));
services.set(IAuxiliaryWindowsMainService, new SyncDescriptor(AuxiliaryWindowsMainService, undefined, false));

// Dialogs
Expand Down Expand Up @@ -1113,7 +1114,7 @@ export class CodeApplication extends Disposable {
const isInternal = isInternalTelemetry(this.productService, this.configurationService);
const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
const appender = new TelemetryAppenderClient(channel);
const commonProperties = resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, sqmId, isInternal);
const commonProperties = resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, sqmId, vsDeviceId, isInternal);
const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService);
const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true };

Expand Down
5 changes: 3 additions & 2 deletions src/vs/code/node/cliProcessMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { UserDataProfilesReadonlyService } from 'vs/platform/userDataProfile/node/userDataProfile';
import { resolveMachineId, resolveSqmId } from 'vs/platform/telemetry/node/telemetryUtils';
import { resolveMachineId, resolveSqmId, resolveVSDeviceId } from 'vs/platform/telemetry/node/telemetryUtils';
import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService';
import { LogService } from 'vs/platform/log/common/logService';
import { LoggerService } from 'vs/platform/log/node/loggerService';
Expand Down Expand Up @@ -186,6 +186,7 @@ class CliMain extends Disposable {
}
}
const sqmId = await resolveSqmId(stateService, logService);
const vsDeviceId = await resolveVSDeviceId(stateService, logService);

// Initialize user data profiles after initializing the state
userDataProfilesService.init();
Expand Down Expand Up @@ -221,7 +222,7 @@ class CliMain extends Disposable {
const config: ITelemetryServiceConfig = {
appenders,
sendErrorTelemetry: false,
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, sqmId, isInternal),
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, sqmId, vsDeviceId, isInternal),
piiPaths: getPiiPathsFromEnvironment(environmentService)
};

Expand Down
2 changes: 1 addition & 1 deletion src/vs/code/node/sharedProcess/sharedProcessMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {

telemetryService = new TelemetryService({
appenders,
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, this.configuration.sqmId, internalTelemetry),
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, this.configuration.sqmId, this.configuration.vsDeviceId, internalTelemetry),
sendErrorTelemetry: true,
piiPaths: getPiiPathsFromEnvironment(environmentService),
}, configurationService, productService);
Expand Down
1 change: 1 addition & 0 deletions src/vs/editor/standalone/browser/standaloneServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,7 @@ class StandaloneTelemetryService implements ITelemetryService {
readonly sessionId = 'someValue.sessionId';
readonly machineId = 'someValue.machineId';
readonly sqmId = 'someValue.sqmId';
readonly vsDeviceId = 'someValue.vsDeviceId';
readonly firstSessionDate = 'someValue.firstSessionDate';
readonly sendErrorTelemetry = false;
setEnabled(): void { }
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/sharedProcess/electron-main/sharedProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class SharedProcess extends Disposable {
constructor(
private readonly machineId: string,
private readonly sqmId: string,
private readonly vsDeviceId: string,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
Expand Down Expand Up @@ -180,6 +181,7 @@ export class SharedProcess extends Disposable {
return {
machineId: this.machineId,
sqmId: this.sqmId,
vsDeviceId: this.vsDeviceId,
codeCachePath: this.environmentMainService.codeCachePath,
profiles: {
home: this.userDataProfilesService.profilesHome,
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/sharedProcess/node/sharedProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface ISharedProcessConfiguration {

readonly sqmId: string;

readonly vsDeviceId: string;

readonly codeCachePath: string | undefined;

readonly args: NativeParsedArgs;
Expand Down
3 changes: 3 additions & 0 deletions src/vs/platform/telemetry/common/commonProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function resolveCommonProperties(
version: string | undefined,
machineId: string | undefined,
sqmId: string | undefined,
vsDeviceId: string | undefined,
isInternalTelemetry: boolean,
product?: string
): ICommonProperties {
Expand All @@ -33,6 +34,8 @@ export function resolveCommonProperties(
result['common.machineId'] = machineId;
// __GDPR__COMMON__ "common.sqmId" : { "endPoint": "SqmMachineId", "classification": "EndUserPseudonymizedInformation", "purpose": "BusinessInsight" }
result['common.sqmId'] = sqmId;
// __GDPR__COMMON__ "common.vsDeviceId" : { "endPoint": "SqmMachineId", "classification": "EndUserPseudonymizedInformation", "purpose": "BusinessInsight" }
result['common.vsDeviceId'] = vsDeviceId;
// __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['sessionID'] = generateUuid() + Date.now();
// __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/telemetry/common/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface ITelemetryService {
readonly sessionId: string;
readonly machineId: string;
readonly sqmId: string;
readonly vsDeviceId: string;
readonly firstSessionDate: string;
readonly msftInternal?: boolean;

Expand Down Expand Up @@ -73,6 +74,7 @@ export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
export const machineIdKey = 'telemetry.machineId';
export const sqmIdKey = 'telemetry.sqmId';
export const vsDeviceIdKey = 'telemetry.vsDeviceId';

// Configuration Keys
export const TELEMETRY_SECTION_ID = 'telemetry';
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/telemetry/common/telemetryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class TelemetryService implements ITelemetryService {
readonly sessionId: string;
readonly machineId: string;
readonly sqmId: string;
readonly vsDeviceId: string;
readonly firstSessionDate: string;
readonly msftInternal: boolean | undefined;

Expand All @@ -58,6 +59,7 @@ export class TelemetryService implements ITelemetryService {
this.sessionId = this._commonProperties['sessionID'] as string;
this.machineId = this._commonProperties['common.machineId'] as string;
this.sqmId = this._commonProperties['common.sqmId'] as string;
this.vsDeviceId = this._commonProperties['common.vsDeviceId'] as string;
this.firstSessionDate = this._commonProperties['common.firstSessionDate'] as string;
this.msftInternal = this._commonProperties['common.msftInternal'] as boolean | undefined;

Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/telemetry/common/telemetryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class NullTelemetryServiceShape implements ITelemetryService {
readonly sessionId = 'someValue.sessionId';
readonly machineId = 'someValue.machineId';
readonly sqmId = 'someValue.sqmId';
readonly vsDeviceId = 'someValue.vsDeviceId';
readonly firstSessionDate = 'someValue.firstSessionDate';
readonly sendErrorTelemetry = false;
publicLog() { }
Expand Down
10 changes: 8 additions & 2 deletions src/vs/platform/telemetry/electron-main/telemetryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/node/state';
import { machineIdKey, sqmIdKey } from 'vs/platform/telemetry/common/telemetry';
import { resolveMachineId as resolveNodeMachineId, resolveSqmId as resolveNodeSqmId } from 'vs/platform/telemetry/node/telemetryUtils';
import { machineIdKey, sqmIdKey, vsDeviceIdKey } from 'vs/platform/telemetry/common/telemetry';
import { resolveMachineId as resolveNodeMachineId, resolveSqmId as resolveNodeSqmId, resolveVSDeviceId as resolveNodeVSDeviceId } from 'vs/platform/telemetry/node/telemetryUtils';

export async function resolveMachineId(stateService: IStateService, logService: ILogService): Promise<string> {
// Call the node layers implementation to avoid code duplication
Expand All @@ -20,3 +20,9 @@ export async function resolveSqmId(stateService: IStateService, logService: ILog
stateService.setItem(sqmIdKey, sqmId);
return sqmId;
}

export async function resolveVSDeviceId(stateService: IStateService, logService: ILogService): Promise<string> {
const vsDeviceId = await resolveNodeVSDeviceId(stateService, logService);
stateService.setItem(vsDeviceIdKey, vsDeviceId);
return vsDeviceId;
}
13 changes: 11 additions & 2 deletions src/vs/platform/telemetry/node/telemetryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/

import { isMacintosh } from 'vs/base/common/platform';
import { getMachineId, getSqmMachineId } from 'vs/base/node/id';
import { getMachineId, getSqmMachineId, getVSDeviceId } from 'vs/base/node/id';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateReadService } from 'vs/platform/state/node/state';
import { machineIdKey, sqmIdKey } from 'vs/platform/telemetry/common/telemetry';
import { machineIdKey, sqmIdKey, vsDeviceIdKey } from 'vs/platform/telemetry/common/telemetry';


export async function resolveMachineId(stateService: IStateReadService, logService: ILogService): Promise<string> {
Expand All @@ -29,3 +29,12 @@ export async function resolveSqmId(stateService: IStateReadService, logService:

return sqmId;
}

export async function resolveVSDeviceId(stateService: IStateReadService, logService: ILogService): Promise<string> {
let vsDeviceId = stateService.getItem<string>(vsDeviceIdKey);
if (typeof vsDeviceId !== 'string') {
vsDeviceId = await getVSDeviceId(logService.error.bind(logService));
}

return vsDeviceId;
}
1 change: 1 addition & 0 deletions src/vs/platform/window/common/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native

machineId: string;
sqmId: string;
vsDeviceId: string;

execPath: string;
backupPath?: string;
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/windows/electron-main/windowsMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
constructor(
private readonly machineId: string,
private readonly sqmId: string,
private readonly vsDeviceId: string,
private readonly initialUserEnv: IProcessEnvironment,
@ILogService private readonly logService: ILogService,
@ILoggerMainService private readonly loggerService: ILoggerMainService,
Expand Down Expand Up @@ -1409,6 +1410,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic

machineId: this.machineId,
sqmId: this.sqmId,
vsDeviceId: this.vsDeviceId,

windowId: -1, // Will be filled in by the window once loaded later

Expand Down
9 changes: 5 additions & 4 deletions src/vs/server/node/serverServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import * as path from 'vs/base/common/path';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { getMachineId, getSqmMachineId } from 'vs/base/node/id';
import { getMachineId, getSqmMachineId, getVSDeviceId } from 'vs/base/node/id';
import { Promises } from 'vs/base/node/pfs';
import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
import { ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net';
Expand Down Expand Up @@ -132,11 +132,12 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
socketServer.registerChannel('userDataProfiles', new RemoteUserDataProfilesServiceChannel(userDataProfilesService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority)));

// Initialize
const [, , machineId, sqmId] = await Promise.all([
const [, , machineId, sqmId, vsDeviceId] = await Promise.all([
configurationService.initialize(),
userDataProfilesService.init(),
getMachineId(logService.error.bind(logService)),
getSqmMachineId(logService.error.bind(logService))
getSqmMachineId(logService.error.bind(logService)),
getVSDeviceId(logService.error.bind(logService))
]);

const extensionHostStatusService = new ExtensionHostStatusService();
Expand All @@ -156,7 +157,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken

const config: ITelemetryServiceConfig = {
appenders: [oneDsAppender],
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, sqmId, isInternal, 'remoteAgent'),
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, sqmId, vsDeviceId, isInternal, 'remoteAgent'),
piiPaths: getPiiPathsFromEnvironment(environmentService)
};
const initialTelemetryLevelArg = environmentService.args['telemetry-level'];
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/common/extHostTelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export class ExtHostTelemetry extends Disposable implements ExtHostTelemetryShap
commonProperties['common.vscodemachineid'] = this.initData.telemetryInfo.machineId;
commonProperties['common.vscodesessionid'] = this.initData.telemetryInfo.sessionId;
commonProperties['common.sqmid'] = this.initData.telemetryInfo.sqmId;
commonProperties['common.vsdeviceid'] = this.initData.telemetryInfo.vsDeviceId;
commonProperties['common.vscodeversion'] = this.initData.version;
commonProperties['common.isnewappinstall'] = isNewAppInstall(this.initData.telemetryInfo.firstSessionDate);
commonProperties['common.product'] = this.initData.environment.appHost;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/test/browser/extHostTelemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ suite('ExtHostTelemetry', function () {
firstSessionDate: '2020-01-01T00:00:00.000Z',
sessionId: 'test',
machineId: 'test',
sqmId: 'test'
sqmId: 'test',
vsDeviceId: 'test'
};

const mockRemote = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface INativeWorkbenchEnvironmentService extends IBrowserWorkbenchEnv
readonly os: IOSConfiguration;
readonly machineId: string;
readonly sqmId: string;
readonly vsDeviceId: string;

// --- Paths
readonly execPath: string;
Expand All @@ -63,6 +64,9 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment
@memoize
get sqmId() { return this.configuration.sqmId; }

@memoize
get vsDeviceId() { return this.configuration.vsDeviceId; }

@memoize
get remoteAuthority() { return this.configuration.remoteAuthority; }

Expand Down
Loading
Loading