Path: blob/main/extensions/copilot/src/extension/power/vscode-node/powerService.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as vscode from 'vscode';6import { ILogService } from '../../../platform/log/common/logService';7import { Emitter } from '../../../util/vs/base/common/event';8import { Disposable, IDisposable, toDisposable } from '../../../util/vs/base/common/lifecycle';9import { IPowerService } from '../common/powerService';1011const RELEASE_DELAY_MS = 2 * 60 * 1000; // 2 minutes1213export class PowerService extends Disposable implements IPowerService {14declare readonly _serviceBrand: undefined;1516private _activeCount = 0;17private _blocker: (vscode.Disposable & { readonly id: number }) | undefined;18private _releaseTimer: ReturnType<typeof setTimeout> | undefined;1920private readonly _onDidSuspend = this._register(new Emitter<void>());21readonly onDidSuspend = this._onDidSuspend.event;2223private readonly _onDidResume = this._register(new Emitter<void>());24readonly onDidResume = this._onDidResume.event;2526constructor(27@ILogService private readonly _logService: ILogService,28) {29super();3031if (typeof vscode.env.power?.onDidSuspend === 'function') {32this._register(vscode.env.power.onDidSuspend(() => this._onDidSuspend.fire()));33this._register(vscode.env.power.onDidResume(() => this._onDidResume.fire()));34}35}3637acquirePowerSaveBlocker(): IDisposable {38this._activeCount++;39this._logService.debug(`[PowerService] Acquired power save blocker, active count: ${this._activeCount}`);4041// Clear any pending release timer42if (this._releaseTimer !== undefined) {43clearTimeout(this._releaseTimer);44this._releaseTimer = undefined;45}4647// Start the blocker if this is the first acquisition48if (this._activeCount === 1) {49this._startBlocker();50}5152let disposed = false;53return toDisposable(() => {54if (disposed) {55return;56}57disposed = true;58this._release();59});60}6162private async _startBlocker(): Promise<void> {63if (this._blocker) {64return;65}6667try {68// Check if the API is available (proposed API, desktop only)69if (typeof vscode.env.power?.startPowerSaveBlocker !== 'function') {70this._logService.debug('[PowerService] Power save blocker API not available');71return;72}7374this._blocker = await vscode.env.power.startPowerSaveBlocker('prevent-app-suspension');75this._logService.debug(`[PowerService] Started power save blocker, id: ${this._blocker.id}`);76} catch (err) {77this._logService.warn(`[PowerService] Failed to start power save blocker: ${err}`);78}79}8081private _release(): void {82this._activeCount--;83this._logService.debug(`[PowerService] Released power save blocker acquisition, active count: ${this._activeCount}`);8485if (this._activeCount <= 0) {86this._activeCount = 0;87this._scheduleStopBlocker();88}89}9091private _scheduleStopBlocker(): void {92if (this._releaseTimer !== undefined) {93return; // Already scheduled94}9596this._logService.debug(`[PowerService] Scheduling power save blocker release in ${RELEASE_DELAY_MS}ms`);97this._releaseTimer = setTimeout(() => {98this._releaseTimer = undefined;99this._stopBlocker();100}, RELEASE_DELAY_MS);101}102103private _stopBlocker(): void {104if (!this._blocker) {105return;106}107108// Don't stop if new acquisitions came in109if (this._activeCount > 0) {110return;111}112113this._logService.debug(`[PowerService] Stopping power save blocker, id: ${this._blocker.id}`);114this._blocker.dispose();115this._blocker = undefined;116}117118override dispose(): void {119if (this._releaseTimer !== undefined) {120clearTimeout(this._releaseTimer);121this._releaseTimer = undefined;122}123if (this._blocker) {124this._blocker.dispose();125this._blocker = undefined;126}127super.dispose();128}129}130131132