@aiot-toolkit/emulator 2.0.6-beta.4 → 2.0.6-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,10 +9,15 @@ export declare const defaultToolsHome: string;
9
9
  export declare const defaultVncPort = 5900;
10
10
  export declare const defaultAdbPort = 5555;
11
11
  export declare const defaultDebugPort = 10055;
12
- export declare const baseUrl = "https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide";
13
- export declare const versionUrl = "https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/versions.json";
14
- export declare const emulatorBaseUrl = "https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/emulator";
15
- export declare const systemImageBaseUrl = "https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/system-images";
12
+ /**
13
+ * 获取 Vela Emulator SDK 相关下载地址
14
+ */
15
+ export declare function getSdkUrl(): Promise<{
16
+ baseUrl: string;
17
+ versionUrl: string;
18
+ emulatorBaseUrl: string;
19
+ systemImageBaseUrl: string;
20
+ }>;
16
21
  /**
17
22
  * vela-release-4.0 : vela 4.0 带 miwear
18
23
  * vela-pre-4.0 : vela 4.0 不带 miwear
@@ -36,11 +41,11 @@ export declare const EmulatorEnvVersion: {
36
41
  tools: string;
37
42
  };
38
43
  /** 获取镜像下载地址 */
39
- export declare function getImageDownloadUrl(): Record<VelaImageType, string>;
44
+ export declare function getImageDownloadUrl(): Promise<Record<VelaImageType, string>>;
40
45
  /**
41
46
  * 获取各种 SKD 最新版本的下载地址;
42
47
  * 镜像地址默认返回 REL 版本的地址,如果需要获取其他版本,请使用
43
48
  * {@link getImageDownloadUrl}
44
49
  */
45
- export declare function getSDKPartDownloadUrl(type: SDKParts): string;
50
+ export declare function getSDKPartDownloadUrl(type: SDKParts): Promise<string>;
46
51
  export { isVelaImageType, isMiwearImageType, getDefaultImage } from '../shared';
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.emulatorBaseUrl = exports.defaultVvdHome = exports.defaultVncPort = exports.defaultToolsHome = exports.defaultSkinHome = exports.defaultSDKHome = exports.defaultQuickappHome = exports.defaultImageHome = exports.defaultEmulatorHome = exports.defaultDebugPort = exports.defaultAdbPort = exports.baseUrl = exports.VelaImageVersionList = exports.EmulatorEnvVersion = void 0;
6
+ exports.defaultVvdHome = exports.defaultVncPort = exports.defaultToolsHome = exports.defaultSkinHome = exports.defaultSDKHome = exports.defaultQuickappHome = exports.defaultImageHome = exports.defaultEmulatorHome = exports.defaultDebugPort = exports.defaultAdbPort = exports.VelaImageVersionList = exports.EmulatorEnvVersion = void 0;
7
7
  Object.defineProperty(exports, "getDefaultImage", {
8
8
  enumerable: true,
9
9
  get: function () {
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "getDefaultImage", {
12
12
  });
13
13
  exports.getImageDownloadUrl = getImageDownloadUrl;
14
14
  exports.getSDKPartDownloadUrl = getSDKPartDownloadUrl;
15
+ exports.getSdkUrl = getSdkUrl;
15
16
  Object.defineProperty(exports, "isMiwearImageType", {
16
17
  enumerable: true,
17
18
  get: function () {
@@ -24,9 +25,9 @@ Object.defineProperty(exports, "isVelaImageType", {
24
25
  return _shared.isVelaImageType;
25
26
  }
26
27
  });
27
- exports.versionUrl = exports.systemImageBaseUrl = void 0;
28
28
  var _os = _interopRequireDefault(require("os"));
29
29
  var _path = _interopRequireDefault(require("path"));
30
+ var _https = _interopRequireDefault(require("https"));
30
31
  var _Vvd = require("../typing/Vvd");
31
32
  var _utils = require("../utils");
32
33
  var _shared = require("../shared");
@@ -41,10 +42,32 @@ const defaultToolsHome = exports.defaultToolsHome = _path.default.resolve(defaul
41
42
  const defaultVncPort = exports.defaultVncPort = 5900;
42
43
  const defaultAdbPort = exports.defaultAdbPort = 5555;
43
44
  const defaultDebugPort = exports.defaultDebugPort = 10055;
44
- const baseUrl = exports.baseUrl = 'https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide';
45
- const versionUrl = exports.versionUrl = 'https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/versions.json';
46
- const emulatorBaseUrl = exports.emulatorBaseUrl = 'https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/emulator';
47
- const systemImageBaseUrl = exports.systemImageBaseUrl = 'https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide/system-images';
45
+
46
+ /**
47
+ * 获取 Vela Emulator SDK 相关下载地址
48
+ */
49
+ async function getSdkUrl() {
50
+ const externalBaseUrl = 'https://vela-ide.cnbj3-fusion.mi-fds.com/vela-ide';
51
+ const internalBaseUrl = 'https://cnbj3-fusion-fds.api.xiaomi.net/vela-ide';
52
+ // 优先使用内网域名,因为云上工程没有外网环境
53
+ let base = internalBaseUrl;
54
+ await new Promise(resolve => {
55
+ _https.default.get(`${base}/versions.json`, {
56
+ timeout: 2000
57
+ }, res => {
58
+ if (res.statusCode !== 200) {
59
+ base = externalBaseUrl;
60
+ }
61
+ resolve();
62
+ });
63
+ });
64
+ return {
65
+ baseUrl: base,
66
+ versionUrl: `${base}/versions.json`,
67
+ emulatorBaseUrl: `${base}/emulator`,
68
+ systemImageBaseUrl: `${base}/system-images`
69
+ };
70
+ }
48
71
 
49
72
  // 不确定vela镜像的发布策略,暂时需要手动更新此列表
50
73
  // 0.0.2和0.0.3版本比较特殊,线上是一个nuttx文件。其他版本都是一个zip包,包含nuttx data.img和vela_source.img
@@ -91,7 +114,7 @@ const VelaImageVersionList = exports.VelaImageVersionList = [{
91
114
  }];
92
115
  const EmulatorEnvVersion = exports.EmulatorEnvVersion = {
93
116
  name: '模拟器资源版本管理',
94
- [_Vvd.SDKParts.EMULATOR]: '0.1.0',
117
+ [_Vvd.SDKParts.EMULATOR]: '0.2.0',
95
118
  [_Vvd.SDKParts.QA]: '0.0.1',
96
119
  [_Vvd.SDKParts.SKINS]: '0.0.12',
97
120
  [_Vvd.SDKParts.SYSTEM_IMAGES]: VelaImageVersionList[0].time,
@@ -100,7 +123,10 @@ const EmulatorEnvVersion = exports.EmulatorEnvVersion = {
100
123
  };
101
124
 
102
125
  /** 获取镜像下载地址 */
103
- function getImageDownloadUrl() {
126
+ async function getImageDownloadUrl() {
127
+ const {
128
+ systemImageBaseUrl
129
+ } = await getSdkUrl();
104
130
  return VelaImageVersionList.reduce((res, t) => {
105
131
  res[t.value] = `${systemImageBaseUrl}/${t.value}/${t.time}/${t.value}.zip`;
106
132
  return res;
@@ -112,7 +138,11 @@ function getImageDownloadUrl() {
112
138
  * 镜像地址默认返回 REL 版本的地址,如果需要获取其他版本,请使用
113
139
  * {@link getImageDownloadUrl}
114
140
  */
115
- function getSDKPartDownloadUrl(type) {
141
+ async function getSDKPartDownloadUrl(type) {
142
+ const {
143
+ emulatorBaseUrl,
144
+ baseUrl
145
+ } = await getSdkUrl();
116
146
  switch (type) {
117
147
  case _Vvd.SDKParts.EMULATOR:
118
148
  const systemOs = _os.default.platform();
@@ -120,7 +150,7 @@ function getSDKPartDownloadUrl(type) {
120
150
  let hostOs = systemOs === 'win32' ? 'windows' : systemOs;
121
151
  return `${emulatorBaseUrl}/v${EmulatorEnvVersion.emulator}/${hostOs}-${hostArch}.zip`;
122
152
  case _Vvd.SDKParts.SYSTEM_IMAGES:
123
- return getImageDownloadUrl()[(0, _shared.getDefaultImage)()];
153
+ return (await getImageDownloadUrl())[(0, _shared.getDefaultImage)()];
124
154
  case _Vvd.SDKParts.QA:
125
155
  case _Vvd.SDKParts.MODEM_SIMULATOR:
126
156
  case _Vvd.SDKParts.SKINS:
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { VvdManager } from './vvd';
1
+ export * from './vvd';
2
2
  export { getSystemArch, tryRun } from './utils';
3
3
  export * from './instance';
4
4
  export * from './typing/Vvd';
package/lib/index.js CHANGED
@@ -4,16 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  var _exportNames = {
7
- VvdManager: true,
8
7
  getSystemArch: true,
9
8
  tryRun: true
10
9
  };
11
- Object.defineProperty(exports, "VvdManager", {
12
- enumerable: true,
13
- get: function () {
14
- return _vvd.VvdManager;
15
- }
16
- });
17
10
  Object.defineProperty(exports, "getSystemArch", {
18
11
  enumerable: true,
19
12
  get: function () {
@@ -27,6 +20,17 @@ Object.defineProperty(exports, "tryRun", {
27
20
  }
28
21
  });
29
22
  var _vvd = require("./vvd");
23
+ Object.keys(_vvd).forEach(function (key) {
24
+ if (key === "default" || key === "__esModule") return;
25
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
26
+ if (key in exports && exports[key] === _vvd[key]) return;
27
+ Object.defineProperty(exports, key, {
28
+ enumerable: true,
29
+ get: function () {
30
+ return _vvd[key];
31
+ }
32
+ });
33
+ });
30
34
  var _utils = require("./utils");
31
35
  var _instance = require("./instance");
32
36
  Object.keys(_instance).forEach(function (key) {
@@ -5,7 +5,8 @@ import { ChildProcessWithoutNullStreams } from 'child_process';
5
5
  declare abstract class CommonEmulatorInstance {
6
6
  imageType: VelaImageType;
7
7
  appDir: string;
8
- static emulatorStartedFlag: RegExp;
8
+ xmsInitedFlag: RegExp;
9
+ xmsStatus: PromiseWithResolvers<void>;
9
10
  static appInstalledFlag: RegExp;
10
11
  static appInstallFailedFlag: RegExp;
11
12
  static appUninstalledFlag: RegExp;
@@ -13,7 +14,7 @@ declare abstract class CommonEmulatorInstance {
13
14
  static isAppInstalled(...args: any[]): boolean;
14
15
  static isAppInstallFailed(log: string): boolean;
15
16
  static isAppUninstalled(log: string, packageName: string): boolean;
16
- static isEmulatorStarted(log: string): boolean;
17
+ isXmsInited(log: string): boolean;
17
18
  sn: string;
18
19
  vvdName: string;
19
20
  debugPort?: number | string;
@@ -18,7 +18,9 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
18
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
19
  class CommonEmulatorInstance {
20
20
  appDir = '/data/quickapp/app';
21
- static emulatorStartedFlag = /quickapp_rpk_installer_init|rpk installer init done|booting completed|Boot completed/;
21
+
22
+ // 判断 xms 服务是否初始化完成的标志
23
+ xmsInitedFlag = /quickapp_rpk_installer_init|rpk installer init done/;
22
24
  static appInstalledFlag = /InstallState_Finished|install finished/;
23
25
  static appInstallFailedFlag = /uv_mq_read_cb: install prepare failed/;
24
26
  static appUninstalledFlag = /uninstalled app/;
@@ -33,8 +35,8 @@ class CommonEmulatorInstance {
33
35
  static isAppUninstalled(log, packageName) {
34
36
  return new RegExp(this.appUninstalledFlag.source + ':\\s+' + packageName).test(log);
35
37
  }
36
- static isEmulatorStarted(log) {
37
- return this.emulatorStartedFlag.test(log);
38
+ isXmsInited(log) {
39
+ return this.xmsInitedFlag.test(log);
38
40
  }
39
41
  constructor(params) {
40
42
  this.sn = `emulator-${params.serialPort}`;
@@ -71,6 +73,16 @@ class CommonEmulatorInstance {
71
73
  this.stderrReadline = r.stderrReadline;
72
74
  this.disposeReadlines = r.dispose;
73
75
  }
76
+ const {
77
+ resolve,
78
+ reject,
79
+ promise
80
+ } = Promise.withResolvers();
81
+ this.xmsStatus = {
82
+ promise,
83
+ resolve,
84
+ reject
85
+ };
74
86
  }
75
87
 
76
88
  /** 安装应用,留给子类实现 */
@@ -85,6 +97,7 @@ class CommonEmulatorInstance {
85
97
 
86
98
  /** 推送指定文件,返回推送结果 */
87
99
  async push(sourcePath, targetPath) {
100
+ await this.xmsStatus.promise;
88
101
  // 1. adb push应用的rpk
89
102
  const pushCmd = `adb -s ${this.sn} push "${sourcePath}" ${targetPath}`;
90
103
  this.logger(`Excuting: ${pushCmd}`);
@@ -3,7 +3,7 @@ import { VelaMiwear5 } from './miwear5';
3
3
  export declare class MiniSound5 extends VelaMiwear5 {
4
4
  imageType: VelaImageType;
5
5
  appDir: string;
6
- static emulatorStartedFlag: RegExp;
6
+ xmsInitedFlag: RegExp;
7
7
  static appStartedFlag: RegExp;
8
8
  /**
9
9
  * 使用 pm 安装快应用
@@ -4,17 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.MiniSound5 = void 0;
7
- var _adb = _interopRequireWildcard(require("@miwt/adb"));
8
- var adbMiwt = _adb;
9
7
  var _Vvd = require("../typing/Vvd");
10
8
  var _miwear = require("./miwear5");
9
+ var adbMiwt = _interopRequireWildcard(require("@miwt/adb"));
11
10
  var _util = require("util");
12
11
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
12
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
14
13
  class MiniSound5 extends _miwear.VelaMiwear5 {
15
14
  imageType = (() => _Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5)();
16
15
  appDir = '/data/app';
17
- static emulatorStartedFlag = /Boot completed/;
16
+ xmsInitedFlag = /Boot completed/;
18
17
  static appStartedFlag = /Start main loop/;
19
18
 
20
19
  /**
@@ -22,6 +21,7 @@ class MiniSound5 extends _miwear.VelaMiwear5 {
22
21
  * @param targeRpk 快应用的rpk文件路径
23
22
  */
24
23
  async install(targeRpk) {
24
+ await this.xmsStatus.promise;
25
25
  const installCmd = `adb -s ${this.sn} shell pm install ${targeRpk}`;
26
26
  this.logger(`Excuting: ${installCmd}`);
27
27
  const res = await adbMiwt.execAdbCmdAsync(installCmd);
@@ -40,8 +40,9 @@ class MiniSound5 extends _miwear.VelaMiwear5 {
40
40
  * 使用 pm 卸载快应用
41
41
  * @param packageName 快应用的包名
42
42
  */
43
- uninstall(packageName) {
44
- const res = (0, _adb.execAdbCmdSync)(`adb -s ${this.sn} shell pm uninstall ${packageName}`);
43
+ async uninstall(packageName) {
44
+ await this.xmsStatus.promise;
45
+ const res = await adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} shell pm uninstall ${packageName}`);
45
46
  if (res.includes('(success 0)')) {
46
47
  return Promise.resolve();
47
48
  } else {
@@ -5,7 +5,7 @@ import { VelaImageType } from '../typing/Vvd';
5
5
  * 针对 Vela正式版(4.0)的镜像
6
6
  */
7
7
  declare class MiwearInstance extends CommonEmulatorInstance {
8
- static emulatorStartedFlag: RegExp;
8
+ xmsInitedFlag: RegExp;
9
9
  static appInstalledFlag: RegExp;
10
10
  imageType: VelaImageType;
11
11
  appDir: string;
@@ -18,7 +18,7 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
18
18
  * 针对 Vela正式版(4.0)的镜像
19
19
  */
20
20
  class MiwearInstance extends _common.default {
21
- static emulatorStartedFlag = /quickapp_rpk_installer_init|rpk installer init done/;
21
+ xmsInitedFlag = /quickapp_rpk_installer_init|rpk installer init done/;
22
22
  static appInstalledFlag = /InstallState_Finished|install finished/;
23
23
  imageType = (() => _Vvd.VelaImageType.REL)();
24
24
  appDir = '/data/quickapp/app';
@@ -33,6 +33,8 @@ class MiwearInstance extends _common.default {
33
33
  * @param targeRpk 快应用的rpk文件路径
34
34
  */
35
35
  async install(targeRpk, options) {
36
+ // 等待 xms 服务初始化完成之后才能进行安装
37
+ await this.xmsStatus.promise;
36
38
  const installCmd = `adb -s ${this.sn} shell pm install ${targeRpk}`;
37
39
  this.logger(`Excuting: ${installCmd}`);
38
40
  adbMiwt.execAdbCmd(installCmd);
@@ -85,7 +87,9 @@ class MiwearInstance extends _common.default {
85
87
  * 使用 pm 卸载快应用
86
88
  * @param packageName 快应用的包名
87
89
  */
88
- uninstall(packageName) {
90
+ async uninstall(packageName) {
91
+ // 等待 xms 服务初始化完成之后才能进行安装
92
+ await this.xmsStatus.promise;
89
93
  adbMiwt.execAdbCmd(`adb -s ${this.sn} shell pm uninstall ${packageName}`);
90
94
  return new Promise((resolve, reject) => {
91
95
  const func = msg => {
@@ -107,6 +111,8 @@ class MiwearInstance extends _common.default {
107
111
  /** 使用 am start 启动快应用 */
108
112
  async startApp(packageName) {
109
113
  let debug = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
114
+ // 等待 xms 服务初始化完成之后才能进行安装
115
+ await this.xmsStatus.promise;
110
116
  // 调试模式需要push一个文件至miwear中
111
117
  if (debug) {
112
118
  const debuggerCfgFile = _path.default.join(__dirname, '../static/debugger_ip.cfg');
@@ -119,6 +125,7 @@ class MiwearInstance extends _common.default {
119
125
  await adbMiwt.execAdbCmdAsync(startCmd);
120
126
  }
121
127
  async closeApp(appName) {
128
+ await this.xmsStatus.promise;
122
129
  const stopCmd = `adb -s ${this.sn} shell am stop ${appName}`;
123
130
  this.logger(`Excuting: ${stopCmd}`);
124
131
  await adbMiwt.execAdbCmdAsync(stopCmd);
@@ -128,7 +135,7 @@ class MiwearInstance extends _common.default {
128
135
  await super.reboot();
129
136
  return new Promise((resolve, reject) => {
130
137
  const func = msg => {
131
- if (MiwearInstance.isEmulatorStarted(msg)) {
138
+ if (this.isXmsInited(msg)) {
132
139
  clearTimeout(timer);
133
140
  resolve();
134
141
  }
@@ -142,6 +149,7 @@ class MiwearInstance extends _common.default {
142
149
  });
143
150
  }
144
151
  async reloadApp(appPackageName) {
152
+ await this.xmsStatus.promise;
145
153
  try {
146
154
  // 2. 执行am stop和am start命令
147
155
  const stopCmd = `adb -s ${this.sn} shell am stop ${appPackageName}`;
@@ -6,7 +6,7 @@ import CommonEmulatorInstance from './common';
6
6
  declare class PreInstance extends CommonEmulatorInstance {
7
7
  imageType: VelaImageType;
8
8
  appDir: string;
9
- static emulatorStartedFlag: RegExp;
9
+ xmsInitedFlag: RegExp;
10
10
  install(rpkPath: string, opt: {
11
11
  packageName: string;
12
12
  size?: number;
@@ -16,8 +16,10 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
16
16
  class PreInstance extends _common.default {
17
17
  imageType = (() => _Vvd.VelaImageType.PRE)();
18
18
  appDir = '/data/quickapp/app';
19
- static emulatorStartedFlag = /(NSH)/;
19
+ xmsInitedFlag = /(NSH)/;
20
20
  async install(rpkPath, opt) {
21
+ await this.xmsStatus.promise;
22
+
21
23
  // 基于 vapp 启动的应用只需要将 rpk 解压到指定的目录下
22
24
  rpkPath = rpkPath || `${this.appDir}/${opt.packageName}.rpk`;
23
25
  const targetPath = `${this.appDir}/${opt.packageName}`;
@@ -1,7 +1,7 @@
1
1
  import { VelaImageType } from '../typing/Vvd';
2
2
  import MiwearInstance from './miwear';
3
3
  export declare class Vela5Instance extends MiwearInstance {
4
- static emulatorStartedFlag: RegExp;
4
+ xmsInitedFlag: RegExp;
5
5
  static appStartedFlag: RegExp;
6
6
  imageType: VelaImageType;
7
7
  appDir: string;
@@ -14,7 +14,7 @@ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return
14
14
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
16
  class Vela5Instance extends _miwear.default {
17
- static emulatorStartedFlag = /booting completed|Boot completed/;
17
+ xmsInitedFlag = /booting completed|Boot completed/;
18
18
  static appStartedFlag = /Start main loop/;
19
19
  imageType = (() => _Vvd.VelaImageType.VELA_WATCH_5)();
20
20
  appDir = '/data/app';
@@ -24,6 +24,7 @@ class Vela5Instance extends _miwear.default {
24
24
  * @param targeRpk 快应用的rpk文件路径
25
25
  */
26
26
  async install(targeRpk) {
27
+ await this.xmsStatus.promise;
27
28
  const installCmd = `adb -s ${this.sn} shell pm install ${targeRpk}`;
28
29
  this.logger(`Excuting: ${installCmd}`);
29
30
  const res = await adbMiwt.execAdbCmdAsync(installCmd);
@@ -40,10 +41,16 @@ class Vela5Instance extends _miwear.default {
40
41
 
41
42
  /** 使用 am start 启动快应用 */
42
43
  async startApp(packageName) {
43
- const startCmd = `adb -s ${this.sn} shell am start ${packageName}`;
44
- this.logger(`Excuting: ${startCmd}`);
45
- adbMiwt.execAdbCmdAsync(startCmd);
46
- return new Promise((resolve, reject) => {
44
+ return new Promise(async (resolve, reject) => {
45
+ let timer = setTimeout(() => {
46
+ this.stdoutReadline.off('line', func);
47
+ this.logger(`Start ${packageName} for ${this.vvdName} timeout`);
48
+ reject('Timeout');
49
+ }, 15 * 1000);
50
+ await this.xmsStatus.promise;
51
+ const startCmd = `adb -s ${this.sn} shell am start ${packageName}`;
52
+ this.logger(`Excuting: ${startCmd}`);
53
+ await adbMiwt.execAdbCmdAsync(startCmd);
47
54
  const clearFn = () => {
48
55
  clearTimeout(timer);
49
56
  this.stdoutReadline.off('line', func);
@@ -62,11 +69,6 @@ class Vela5Instance extends _miwear.default {
62
69
  reject(_shared.RpkStartFailedReason.getManifestFailed);
63
70
  }
64
71
  };
65
- let timer = setTimeout(() => {
66
- this.stdoutReadline.off('line', func);
67
- this.logger(`Start ${packageName} for ${this.vvdName} timeout`);
68
- reject('Timeout');
69
- }, 8 * 1000);
70
72
  this.stdoutReadline.on('line', func);
71
73
  });
72
74
  }
@@ -27,8 +27,9 @@ export interface IVvdParams {
27
27
  flavor?: string;
28
28
  density?: string;
29
29
  customLcdRadius?: string;
30
- imageType: VelaImageType;
30
+ imageType?: VelaImageType;
31
31
  skinInfo?: EmulatorSkin;
32
+ marketName?: string;
32
33
  }
33
34
  export interface EmulatorPart {
34
35
  display: {
@@ -10,7 +10,10 @@ var _protoLoader = require("@grpc/proto-loader");
10
10
  var _grpcError = require("./grpcError");
11
11
  var _grpcJs = require("@grpc/grpc-js");
12
12
  var _protoTypes = require("./types/proto-types");
13
+ var _connectivityState = require("@grpc/grpc-js/build/src/connectivity-state");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ // eslint-disable-next-line no-restricted-imports
16
+
14
17
  const AuthorizationKey = exports.AuthorizationKey = 'Authorization';
15
18
  class GrpcEmulator {
16
19
  connected = false;
@@ -47,24 +50,53 @@ class GrpcEmulator {
47
50
  getAuthMeta() {
48
51
  return this.authMate;
49
52
  }
50
- waitForReady() {
53
+ async waitForReady() {
51
54
  if (this.connected) {
52
- return Promise.resolve(true);
55
+ return true;
56
+ }
57
+ const channel = this.client.getChannel();
58
+ const curState = channel.getConnectivityState(true);
59
+ if (curState === _connectivityState.ConnectivityState.READY) {
60
+ return true;
53
61
  }
54
- const deadline = new Date();
55
- deadline.setMinutes(deadline.getMinutes() + 2); // 2 minutes timeout
62
+ const {
63
+ resolve,
64
+ reject,
65
+ promise
66
+ } = Promise.withResolvers();
67
+ let count = 0;
68
+ const watcher = () => {
69
+ if (++count >= 5) {
70
+ return reject(new Error('gRPC connection failed'));
71
+ }
72
+ const deadline = new Date();
73
+ deadline.setMinutes(deadline.getMinutes() + 2); // 2 minutes timeout
56
74
 
57
- return new Promise((resolve, reject) => {
58
- this.client.waitForReady(deadline, err => {
59
- if (err) {
60
- this.connected = false;
61
- console.error(err);
62
- return reject(err);
75
+ channel.watchConnectivityState(curState, deadline, e => {
76
+ if (e) {
77
+ reject(e);
78
+ }
79
+ const newState = channel.getConnectivityState(true);
80
+ switch (newState) {
81
+ case _connectivityState.ConnectivityState.TRANSIENT_FAILURE:
82
+ reject(new Error('gRPC connection failed'));
83
+ break;
84
+ case _connectivityState.ConnectivityState.READY:
85
+ this.connected = true;
86
+ resolve(true);
87
+ break;
88
+ case _connectivityState.ConnectivityState.SHUTDOWN:
89
+ reject(new Error('gRPC connection shutdown'));
90
+ break;
91
+ case _connectivityState.ConnectivityState.CONNECTING:
92
+ watcher();
93
+ default:
94
+ break;
63
95
  }
64
- this.connected = true;
65
- resolve(true);
66
96
  });
67
- });
97
+ };
98
+ watcher();
99
+ return promise;
68
100
  }
69
101
  async streamScreenshot(imageFormat) {
70
102
  await this.waitForReady();
@@ -5,6 +5,17 @@ import { findInstance } from '../instance';
5
5
  import type { DownloadFileOptions } from 'ipull';
6
6
  import { GrpcEmulator } from './grpc';
7
7
  export declare const isHeadlessEnvironment: () => boolean;
8
+ export interface StartVvdRes {
9
+ coldBoot: boolean;
10
+ emulatorInstance: ReturnType<typeof findInstance>;
11
+ /**
12
+ * @deprecated use velaAgent instead
13
+ */
14
+ getAgent: () => GrpcEmulator;
15
+ grpcConfig: EmulatorConfig;
16
+ velaAgent: GrpcEmulator;
17
+ imageType: VelaImageType;
18
+ }
8
19
  export declare class VvdManager {
9
20
  private vvdHome;
10
21
  private sdkHome;
@@ -53,12 +64,7 @@ export declare class VvdManager {
53
64
  getEmulatorBinPath(sdkHome: string): string;
54
65
  oldEmulatorMigrate(vvdName: string): Promise<void>;
55
66
  getVvdStartCmd(options: IStartOptions | IStartWithSerialPort): Promise<string>;
56
- startVvd(options: IStartOptions | IStartWithSerialPort): Promise<{
57
- coldBoot: boolean;
58
- emulatorInstance: ReturnType<typeof findInstance>;
59
- getAgent: () => GrpcEmulator;
60
- grpcConfig: EmulatorConfig;
61
- }>;
67
+ startVvd(options: IStartOptions | IStartWithSerialPort): Promise<StartVvdRes>;
62
68
  stopVvd(name: string, timeout?: number): Promise<void>;
63
69
  /** 获取模拟器平台的名称,darwin-aarch64 linux-aarch64 windows-x86_64等 */
64
70
  getEmulatorPlatform(): string;
package/lib/vvd/index.js CHANGED
@@ -100,7 +100,8 @@ class VvdManager {
100
100
  density,
101
101
  imageDir: imagePath = _constants.defaultImageHome,
102
102
  customLcdRadius,
103
- imageType
103
+ imageType,
104
+ marketName
104
105
  } = vvdParams;
105
106
  const vvdDir = _path.default.resolve(this.vvdHome, `${vvdName}.vvd`);
106
107
  const vvdIni = _path.default.resolve(this.vvdHome, `${vvdName}.ini`);
@@ -112,11 +113,11 @@ class VvdManager {
112
113
  configIniJson['abi.type'] = abiType;
113
114
  configIniJson['avd.ini.displayname'] = vvdName;
114
115
  configIniJson['hw.cpu.arch'] = arch;
115
- configIniJson['hw.lcd.shape'] = shape;
116
- configIniJson['hw.device.flavor'] = flavor;
117
- configIniJson['hw.lcd.density'] = density;
118
- configIniJson['ide.lcd.radius'] = customLcdRadius;
119
- configIniJson['ide.image.type'] = imageType;
116
+ if (shape) configIniJson['hw.lcd.shape'] = shape;
117
+ if (flavor) configIniJson['hw.device.flavor'] = flavor;
118
+ if (density) configIniJson['hw.lcd.density'] = density;
119
+ if (customLcdRadius) configIniJson['ide.lcd.radius'] = customLcdRadius;
120
+ if (imageType) configIniJson['ide.image.type'] = imageType;
120
121
  if (skin) {
121
122
  delete configIniJson['hw.lcd.height'];
122
123
  delete configIniJson['hw.lcd.width'];
@@ -130,7 +131,9 @@ class VvdManager {
130
131
  delete configIniJson['skin.name'];
131
132
  delete configIniJson['skin.path'];
132
133
  }
133
-
134
+ if (marketName) {
135
+ configIniJson['product.marketname'] = marketName;
136
+ }
134
137
  // 默认使用 'image.sysdir.2' 自定义使用 'image.sysdir.1'
135
138
  configIniJson['image.sysdir.2'] = imagePath;
136
139
  try {
@@ -181,8 +184,7 @@ class VvdManager {
181
184
  width: '',
182
185
  skin: '',
183
186
  imageDir: '',
184
- customLcdRadius: '',
185
- imageType: _Vvd.VelaImageType.VELA_MIWEAR_WATCH_5
187
+ customLcdRadius: ''
186
188
  };
187
189
  let currVvdDir = this.getVvdDir(vvdName);
188
190
  const configIni = _path.default.resolve(currVvdDir, 'config.ini');
@@ -530,13 +532,33 @@ class VvdManager {
530
532
  const onErrout = options.stderrCallback || console.log;
531
533
  const e = runningVvds.find(e => e['avd.name'] === vvdName);
532
534
  const vvdInfo = this.getVvdInfo(vvdName);
535
+ const getImageType = async serial => {
536
+ if (vvdInfo.imageType) return vvdInfo.imageType;
537
+ // 如果不是通过 IDE 创建的模拟器,没有 imageType 字段,需要智能嗅探镜像类型
538
+ try {
539
+ const res = await (0, _adb.execAdbCmdAsync)(`adb -s emulator-${serial} shell uname -a`, {
540
+ timeout: 3000,
541
+ encoding: 'utf-8'
542
+ });
543
+ if (res.includes('miwear')) {
544
+ return _Vvd.VelaImageType.VELA_MIWEAR_WATCH_5;
545
+ }
546
+ if (res.includes('smartspeaker')) {
547
+ return _Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5;
548
+ }
549
+ } catch (error) {
550
+ return _Vvd.VelaImageType.VELA_WATCH_5;
551
+ }
552
+ return _Vvd.VelaImageType.VELA_WATCH_5;
553
+ };
533
554
 
534
555
  // 该模拟器已经启动,则创建一个日志流返回
535
556
  if (e) {
536
557
  // 找出来它原来使用的 debugPort
537
558
  const regex = /hostfwd=tcp:(.*?):(\d+)-10\.0\.2\.15:101/;
538
559
  const debugPort = e.cmdline?.match(regex)?.[2];
539
- const emulatorInstance = (0, _instance.findInstance)(vvdInfo.imageType, {
560
+ const imageType = await getImageType(e['port.serial']);
561
+ const emulatorInstance = (0, _instance.findInstance)(imageType, {
540
562
  serialPort: e['port.serial'],
541
563
  vvdName: vvdName,
542
564
  onStdout,
@@ -544,11 +566,16 @@ class VvdManager {
544
566
  debugPort,
545
567
  customLogger: options.customLogger
546
568
  });
569
+ const velaAgent = (0, _grpc.createGrpcClient)(e);
570
+ await velaAgent.waitForReady();
571
+ emulatorInstance.xmsStatus.resolve();
547
572
  return {
548
573
  coldBoot: false,
549
574
  emulatorInstance,
550
575
  getAgent: () => (0, _grpc.createGrpcClient)(e),
551
- grpcConfig: e
576
+ grpcConfig: e,
577
+ velaAgent,
578
+ imageType
552
579
  };
553
580
  }
554
581
 
@@ -557,65 +584,85 @@ class VvdManager {
557
584
  const spawnArgs = cmd.split(' ');
558
585
  const spawnBin = spawnArgs.shift();
559
586
  logger(`Start CMD: ${cmd}`);
560
- const InstanceCalss = (0, _instance.getInstanceClass)(vvdInfo.imageType);
561
- const func = InstanceCalss.isEmulatorStarted.bind(InstanceCalss);
562
- return new Promise((resolve, reject) => {
563
- const emulatorProcess = (0, _child_process.spawn)(spawnBin, spawnArgs, {
564
- stdio: 'pipe',
565
- shell: true,
566
- cwd: this.sdkHome
567
- });
568
- if (options.origin === _Instance.IStartOrigin.Terminal) {
569
- process.stdin.pipe(emulatorProcess.stdin);
570
- }
571
-
572
- // 利用 readline 接口可解决子进程日志换行的问题
573
- const readlines = (0, _logcat.attachReadline)(emulatorProcess, onStdout, onErrout);
574
- const emulatorStartedHandler = msg => {
575
- if (func(msg)) {
576
- const e = (0, _emulatorutil.getRunningAvdConfigByName)(vvdName);
577
- if (e) {
578
- const emulatorInstance = (0, _instance.findInstance)(vvdInfo.imageType, {
579
- serialPort: e['port.serial'],
580
- vvdName: vvdName,
581
- logcatProcess: emulatorProcess,
582
- ...readlines,
583
- onStdout,
584
- onErrout,
585
- debugPort: options.debugPort,
586
- customLogger: options.customLogger
587
- });
588
- logger(`${options.vvdName} started successfully`);
589
- readlines.stdoutReadline.off('line', emulatorStartedHandler);
590
- resolve({
591
- coldBoot: true,
592
- emulatorInstance,
593
- getAgent: () => (0, _grpc.createGrpcClient)(e),
594
- grpcConfig: e
595
- });
587
+ const {
588
+ resolve,
589
+ reject,
590
+ promise
591
+ } = Promise.withResolvers();
592
+ const emulatorProcess = (0, _child_process.spawn)(spawnBin, spawnArgs, {
593
+ stdio: 'pipe',
594
+ shell: true,
595
+ cwd: this.sdkHome
596
+ });
597
+ if (options.origin === _Instance.IStartOrigin.Terminal) {
598
+ process.stdin.pipe(emulatorProcess.stdin);
599
+ }
600
+ // 利用 readline 接口可解决子进程日志换行的问题
601
+ const readlines = (0, _logcat.attachReadline)(emulatorProcess, onStdout, onErrout);
602
+ const emulatorStartedHandler = async msg => {
603
+ if (msg.includes('INFO | Boot completed')) {
604
+ const e = (0, _emulatorutil.getRunningAvdConfigByName)(vvdName);
605
+ if (e) {
606
+ const imageType = await getImageType(e['port.serial']);
607
+ const emulatorInstance = (0, _instance.findInstance)(imageType, {
608
+ serialPort: e['port.serial'],
609
+ vvdName: vvdName,
610
+ logcatProcess: emulatorProcess,
611
+ ...readlines,
612
+ onStdout,
613
+ onErrout,
614
+ debugPort: options.debugPort,
615
+ customLogger: options.customLogger
616
+ });
617
+ readlines.stdoutReadline.off('line', emulatorStartedHandler);
618
+ const velaAgent = (0, _grpc.createGrpcClient)(e);
619
+ await velaAgent.waitForReady();
620
+ if (imageType.includes('miwear')) {
621
+ // 这个时候系统启动成功了,但是 rpk 安装程序还没准备好
622
+
623
+ const miwearXmsReadyHander = msg => {
624
+ const startedFunc = emulatorInstance.isXmsInited.bind(emulatorInstance);
625
+ if (startedFunc(msg)) {
626
+ readlines.stdoutReadline.off('line', miwearXmsReadyHander);
627
+ emulatorInstance.xmsStatus.resolve();
628
+ }
629
+ };
630
+ readlines.stdoutReadline.on('line', miwearXmsReadyHander);
596
631
  } else {
597
- reject('get emulator running config failed');
632
+ emulatorInstance.xmsStatus.resolve();
598
633
  }
634
+ logger(`${options.vvdName} started successfully`);
635
+ resolve({
636
+ coldBoot: true,
637
+ emulatorInstance,
638
+ getAgent: () => (0, _grpc.createGrpcClient)(e),
639
+ grpcConfig: e,
640
+ velaAgent,
641
+ imageType
642
+ });
643
+ } else {
644
+ reject('get emulator running config failed');
599
645
  }
600
- };
601
- readlines.stdoutReadline.on('line', emulatorStartedHandler);
646
+ }
647
+ };
648
+ readlines.stdoutReadline.on('line', emulatorStartedHandler);
602
649
 
603
- // 监听模拟器的退出事件
604
- emulatorProcess.on('exit', code => {
605
- logger(`${options.vvdName} emulator exited with code ${code}`);
606
- if (options.exitCallback) {
607
- options.exitCallback(code);
608
- }
609
- readlines.dispose();
610
- reject();
611
- });
650
+ // 监听模拟器的退出事件
651
+ emulatorProcess.on('exit', code => {
652
+ logger(`${options.vvdName} emulator exited with code ${code}`);
653
+ if (options.exitCallback) {
654
+ options.exitCallback(code);
655
+ }
656
+ readlines.dispose();
657
+ reject();
658
+ });
612
659
 
613
- // 监听模拟器的错误事件
614
- emulatorProcess.on('error', err => {
615
- readlines.dispose();
616
- reject(err);
617
- });
660
+ // 监听模拟器的错误事件
661
+ emulatorProcess.on('error', err => {
662
+ readlines.dispose();
663
+ reject(err);
618
664
  });
665
+ return promise;
619
666
  }
620
667
  stopVvd(name) {
621
668
  let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10 * 1000;
@@ -791,14 +838,17 @@ class VvdManager {
791
838
  */
792
839
  async downloadSDK(opt) {
793
840
  const updateList = opt.force ? Object.values(_Vvd.SDKParts) : await this.hasSDKPartUpdate();
794
- let urls = updateList.map(t => ({
795
- name: t,
796
- url: (0, _constants.getSDKPartDownloadUrl)(t)
797
- }));
841
+ let urls = [];
842
+ for (const t of updateList) {
843
+ urls.push({
844
+ name: t,
845
+ url: await (0, _constants.getSDKPartDownloadUrl)(t)
846
+ });
847
+ }
798
848
  if (opt.imageTypeArr) {
799
849
  for (const imgType of opt.imageTypeArr) {
800
850
  const needsUpdate = await this.isLocalImageNeedUpdate(imgType);
801
- const downloadUrl = (0, _constants.getImageDownloadUrl)()[imgType];
851
+ const downloadUrl = (await (0, _constants.getImageDownloadUrl)())[imgType];
802
852
  // 需要更新并且urls中不存在则添加
803
853
  if (needsUpdate && urls.findIndex(u => u.url === downloadUrl) < 0) {
804
854
  urls.push({
@@ -860,7 +910,7 @@ class VvdManager {
860
910
 
861
911
  /** 下载vela系统镜像 */
862
912
  async downloadImage(imageId, opt) {
863
- const downloadUrls = (0, _constants.getImageDownloadUrl)();
913
+ const downloadUrls = await (0, _constants.getImageDownloadUrl)();
864
914
  const u = downloadUrls[imageId];
865
915
  const downloader = await (await ipull).downloadFile({
866
916
  url: u,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/emulator",
3
- "version": "2.0.6-beta.4",
3
+ "version": "2.0.6-beta.6",
4
4
  "description": "vela emulator tool.",
5
5
  "homepage": "",
6
6
  "license": "ISC",
@@ -32,7 +32,7 @@
32
32
  "emulator"
33
33
  ],
34
34
  "dependencies": {
35
- "@aiot-toolkit/shared-utils": "2.0.6-beta.4",
35
+ "@aiot-toolkit/shared-utils": "2.0.6-beta.6",
36
36
  "@grpc/grpc-js": "^1.13.3",
37
37
  "@grpc/proto-loader": "^0.7.13",
38
38
  "@miwt/adb": "0.10.5",
@@ -49,5 +49,5 @@
49
49
  "@types/adm-zip": "^0.5.5",
50
50
  "@types/ini": "^4.1.1"
51
51
  },
52
- "gitHead": "1acc8279ba3c5995aebe3a97a6b33154086f09d6"
52
+ "gitHead": "71dfc780e74e71df4d731300e7c0d6ea9e494358"
53
53
  }