s-blog

VSCode 检查更新机制完整流程

ssssmy · 2026-06-05 · 6 min · VsCode插件开发

梳理 VSCode(Win32)从启动加载更新服务,到检查、下载、安装更新的完整链路,供二次开发自建更新源时参考。

一、启动加载

CodeApplication.startup()src/vs/code/electron-main/app.ts)中依次:初始化服务 → 初始化管道 → 打开窗口后初始化更新服务。

// Services
const appInstantiationService = await this.initServices(machineId, sharedProcess, sharedProcessReady);
// Init Channels
appInstantiationService.invokeFunction((accessor) => this.initChannels(accessor, mainProcessElectronServer, sharedProcessClient));
// Post Open Windows Tasks
appInstantiationService.invokeFunction((accessor) => this.afterWindowOpen(accessor, sharedProcess));

初始化服务

CodeApplication.initServices() 通过 process.platform 判断平台(win32),加载对应更新服务:

services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));

初始化管道

CodeApplication.initChannels()

const updateChannel = new UpdateChannel(accessor.get(IUpdateService));
mainProcessElectronServer.registerChannel('update', updateChannel);

管道方法:checkForUpdates / downloadUpdate / applyUpdate / quitAndInstall / _getInitialState / isLatestVersion

初始化更新服务

CodeApplication.afterWindowOpen() 调用 updateService.initialize()。注意非构建模式(运行源码)不会启用更新

if (!this.environmentMainService.isBuilt) {
  return; // updates are never enabled when running out of sources
}

更新源 URL 由 buildUpdateFeedUrl(quality) 构建(updateService.win32.ts),自建更新时替换为自己的服务地址(如 http://<更新服务>/api/update/win32-x64-archive/stable/...)。

protected buildUpdateFeedUrl(quality: string): string | undefined {
  let platform = 'win32';
  if (process.arch !== 'ia32') platform += `-${process.arch}`;
  if (getUpdateType() === UpdateType.Archive) platform += '-archive';
  else if (this.productService.target === 'user') platform += '-user';
  return createUpdateURL(platform, quality, this.productService);
}

二、检查更新

界面触发「检查更新…」→ 命令 update.checkForVSCodeUpdateupdate.ts)→ 执行 this.updateService.checkForUpdates(sessionId)update.browser/update.ts)。

最终走到 Win32 的 doCheckForUpdates()updateService.win32.ts):

protected doCheckForUpdates(context: any): void {
  if (!this.url) return;                        // 无更新源直接返回
  this.setState(State.CheckingForUpdates(context));
  this.requestService.request({ url: this.url }, CancellationToken.None)
    .then<IUpdate | null>(asJson)
    .then(update => {
      const updateType = getUpdateType();
      // 校验更新信息是否完整
      if (!update || !update.url || !update.version || !update.productVersion) {
        this.setState(State.Idle(updateType));
        return Promise.resolve(null);
      }
      // 安装包模式:仅提示可下载
      if (updateType === UpdateType.Archive) {
        this.setState(State.AvailableForDownload(update));
        return Promise.resolve(null);
      }
      this.setState(State.Downloading(update));
      // 清理被占用的旧安装包 → 取下载路径 → 不存在则下载 → 校验 hash → 重命名
      return this.cleanup(update.version).then(() =>
        this.getUpdatePackagePath(update.version).then(updatePackagePath =>
          pfs.exists(updatePackagePath).then(exists => {
            if (exists) return Promise.resolve(updatePackagePath);
            const downloadPath = `${updatePackagePath}.tmp`;
            return this.requestService.request({ url: update.url }, CancellationToken.None)
              .then(context => this.fileService.writeFile(URI.file(downloadPath), context.stream))
              .then(update.hash ? () => checksum(downloadPath, update.hash) : () => undefined)
              .then(() => fs.promises.rename(downloadPath, updatePackagePath))
              .then(() => updatePackagePath);
          })
        ).then(packagePath => {
          const fastUpdatesEnabled = this.configurationService.getValue<boolean>('update.enableWindowsBackgroundUpdates');
          this.availableUpdate = { packagePath };
          if (fastUpdatesEnabled && update.supportsFastUpdate) {
            if (this.productService.target === 'user') this.doApplyUpdate();   // 快速更新
            else this.setState(State.Downloaded(update));
          } else {
            this.setState(State.Ready(update));                                // 提示重启安装
          }
        })
      );
    });
}

三、更新源响应格式

更新源(this.url)返回的 JSON 用于判断是否有更新(version 与本地 product.json 的 commit 字段不一致即视为有更新):

{
  "url": "https://.../VSCodeUserSetup-x64-1.63.2.exe",
  "name": "1.63.2",
  "version": "899d46d82c4c95423fb7e10e68eba52050e30ba3",
  "productVersion": "1.63.2",
  "hash": "096e2827cc80f50ed8f0af8dcc3daab521f689c7",
  "timestamp": 1639560982409,
  "sha256hash": "e48536b5cab43e08b75b75b89b71a0923e2a28a64f51c53e1a49ec025749eb6b",
  "supportsFastUpdate": true
}

其中 stable 来自 product.json 的 quality 字段;version 对应 commit 字段(VSCode GitHub 对应版本的 tag)。

附:安装包 hash 校验

import * as fs from 'fs';
import * as crypto from 'crypto';

function checksum(path: string) {
  const input = fs.createReadStream(path);
  const hash = crypto.createHash('sha1');
  input.pipe(hash);
  hash.once('data', (data: Buffer) => console.log(data.toString('hex')));
}

原文链接:https://www.ssssmy.com/notes/mo-dou-ide-yuan-ma-vscode-jian-cha-geng-xin-ji-zhi-wan-zheng-liu-cheng