@aiot-toolkit/emulator 2.0.6-beta.3 → 2.0.6-beta.5
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.
- package/lib/emulatorutil/constants.d.ts +12 -6
- package/lib/emulatorutil/constants.js +44 -12
- package/lib/emulatorutil/running.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +11 -7
- package/lib/instance/common.d.ts +3 -2
- package/lib/instance/common.js +16 -3
- package/lib/instance/minisound.d.ts +1 -1
- package/lib/instance/minisound.js +15 -7
- package/lib/instance/miwear.d.ts +1 -1
- package/lib/instance/miwear.js +12 -4
- package/lib/instance/pre.d.ts +1 -1
- package/lib/instance/pre.js +3 -1
- package/lib/instance/vela5.d.ts +1 -1
- package/lib/instance/vela5.js +12 -10
- package/lib/static/avdConfigIni.json +1 -1
- package/lib/typing/Vvd.d.ts +4 -2
- package/lib/typing/Vvd.js +1 -0
- package/lib/vvd/grpc/index.d.ts +0 -1
- package/lib/vvd/grpc/index.js +46 -13
- package/lib/vvd/index.d.ts +12 -6
- package/lib/vvd/index.js +144 -77
- package/package.json +3 -3
|
@@ -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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export declare
|
|
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
|
|
@@ -33,13 +38,14 @@ export declare const EmulatorEnvVersion: {
|
|
|
33
38
|
skins: string;
|
|
34
39
|
"system-images": string;
|
|
35
40
|
modem_simulator: string;
|
|
41
|
+
tools: string;
|
|
36
42
|
};
|
|
37
43
|
/** 获取镜像下载地址 */
|
|
38
|
-
export declare function getImageDownloadUrl(): Record<VelaImageType, string
|
|
44
|
+
export declare function getImageDownloadUrl(): Promise<Record<VelaImageType, string>>;
|
|
39
45
|
/**
|
|
40
46
|
* 获取各种 SKD 最新版本的下载地址;
|
|
41
47
|
* 镜像地址默认返回 REL 版本的地址,如果需要获取其他版本,请使用
|
|
42
48
|
* {@link getImageDownloadUrl}
|
|
43
49
|
*/
|
|
44
|
-
export declare function getSDKPartDownloadUrl(type: SDKParts): string
|
|
50
|
+
export declare function getSDKPartDownloadUrl(type: SDKParts): Promise<string>;
|
|
45
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.
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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,15 +114,19 @@ const VelaImageVersionList = exports.VelaImageVersionList = [{
|
|
|
91
114
|
}];
|
|
92
115
|
const EmulatorEnvVersion = exports.EmulatorEnvVersion = {
|
|
93
116
|
name: '模拟器资源版本管理',
|
|
94
|
-
[_Vvd.SDKParts.EMULATOR]: '0.
|
|
117
|
+
[_Vvd.SDKParts.EMULATOR]: '0.2.0',
|
|
95
118
|
[_Vvd.SDKParts.QA]: '0.0.1',
|
|
96
|
-
[_Vvd.SDKParts.SKINS]: '0.0.
|
|
119
|
+
[_Vvd.SDKParts.SKINS]: '0.0.12',
|
|
97
120
|
[_Vvd.SDKParts.SYSTEM_IMAGES]: VelaImageVersionList[0].time,
|
|
98
|
-
[_Vvd.SDKParts.MODEM_SIMULATOR]: '0.0.3'
|
|
121
|
+
[_Vvd.SDKParts.MODEM_SIMULATOR]: '0.0.3',
|
|
122
|
+
[_Vvd.SDKParts.TOOLS]: '0.0.3'
|
|
99
123
|
};
|
|
100
124
|
|
|
101
125
|
/** 获取镜像下载地址 */
|
|
102
|
-
function getImageDownloadUrl() {
|
|
126
|
+
async function getImageDownloadUrl() {
|
|
127
|
+
const {
|
|
128
|
+
systemImageBaseUrl
|
|
129
|
+
} = await getSdkUrl();
|
|
103
130
|
return VelaImageVersionList.reduce((res, t) => {
|
|
104
131
|
res[t.value] = `${systemImageBaseUrl}/${t.value}/${t.time}/${t.value}.zip`;
|
|
105
132
|
return res;
|
|
@@ -111,7 +138,11 @@ function getImageDownloadUrl() {
|
|
|
111
138
|
* 镜像地址默认返回 REL 版本的地址,如果需要获取其他版本,请使用
|
|
112
139
|
* {@link getImageDownloadUrl}
|
|
113
140
|
*/
|
|
114
|
-
function getSDKPartDownloadUrl(type) {
|
|
141
|
+
async function getSDKPartDownloadUrl(type) {
|
|
142
|
+
const {
|
|
143
|
+
emulatorBaseUrl,
|
|
144
|
+
baseUrl
|
|
145
|
+
} = await getSdkUrl();
|
|
115
146
|
switch (type) {
|
|
116
147
|
case _Vvd.SDKParts.EMULATOR:
|
|
117
148
|
const systemOs = _os.default.platform();
|
|
@@ -119,10 +150,11 @@ function getSDKPartDownloadUrl(type) {
|
|
|
119
150
|
let hostOs = systemOs === 'win32' ? 'windows' : systemOs;
|
|
120
151
|
return `${emulatorBaseUrl}/v${EmulatorEnvVersion.emulator}/${hostOs}-${hostArch}.zip`;
|
|
121
152
|
case _Vvd.SDKParts.SYSTEM_IMAGES:
|
|
122
|
-
return getImageDownloadUrl()[(0, _shared.getDefaultImage)()];
|
|
153
|
+
return (await getImageDownloadUrl())[(0, _shared.getDefaultImage)()];
|
|
123
154
|
case _Vvd.SDKParts.QA:
|
|
124
155
|
case _Vvd.SDKParts.MODEM_SIMULATOR:
|
|
125
156
|
case _Vvd.SDKParts.SKINS:
|
|
157
|
+
case _Vvd.SDKParts.TOOLS:
|
|
126
158
|
return `${baseUrl}/${type}/v${EmulatorEnvVersion[type]}/${type}.zip`;
|
|
127
159
|
}
|
|
128
160
|
}
|
|
@@ -54,7 +54,7 @@ function resolveLinuxPath() {
|
|
|
54
54
|
for (const pattern of linuxPatterns) {
|
|
55
55
|
if (!pattern) continue;
|
|
56
56
|
const dir = resolvePath(pattern);
|
|
57
|
-
if (dir && _fs.default.existsSync(dir) && _fs.default.
|
|
57
|
+
if (dir && _fs.default.existsSync(dir) && _fs.default.statSync(dir).isDirectory()) {
|
|
58
58
|
return dir;
|
|
59
59
|
}
|
|
60
60
|
}
|
package/lib/index.d.ts
CHANGED
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) {
|
package/lib/instance/common.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { ChildProcessWithoutNullStreams } from 'child_process';
|
|
|
5
5
|
declare abstract class CommonEmulatorInstance {
|
|
6
6
|
imageType: VelaImageType;
|
|
7
7
|
appDir: string;
|
|
8
|
-
|
|
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
|
-
|
|
17
|
+
isXmsInited(log: string): boolean;
|
|
17
18
|
sn: string;
|
|
18
19
|
vvdName: string;
|
|
19
20
|
debugPort?: number | string;
|
package/lib/instance/common.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
37
|
-
return this.
|
|
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}`);
|
|
@@ -4,24 +4,31 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.MiniSound5 = void 0;
|
|
7
|
-
var _adb = require("@miwt/adb");
|
|
8
7
|
var _Vvd = require("../typing/Vvd");
|
|
9
8
|
var _miwear = require("./miwear5");
|
|
9
|
+
var adbMiwt = _interopRequireWildcard(require("@miwt/adb"));
|
|
10
|
+
var _util = require("util");
|
|
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); }
|
|
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; }
|
|
10
13
|
class MiniSound5 extends _miwear.VelaMiwear5 {
|
|
11
14
|
imageType = (() => _Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5)();
|
|
12
15
|
appDir = '/data/app';
|
|
13
|
-
|
|
16
|
+
xmsInitedFlag = /Boot completed/;
|
|
14
17
|
static appStartedFlag = /Start main loop/;
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* 使用 pm 安装快应用
|
|
18
21
|
* @param targeRpk 快应用的rpk文件路径
|
|
19
22
|
*/
|
|
20
|
-
install(targeRpk) {
|
|
23
|
+
async install(targeRpk) {
|
|
24
|
+
await this.xmsStatus.promise;
|
|
21
25
|
const installCmd = `adb -s ${this.sn} shell pm install ${targeRpk}`;
|
|
22
26
|
this.logger(`Excuting: ${installCmd}`);
|
|
23
|
-
const res =
|
|
24
|
-
|
|
27
|
+
const res = await adbMiwt.execAdbCmdAsync(installCmd);
|
|
28
|
+
await (0, _util.promisify)(process.nextTick)();
|
|
29
|
+
this.logger(`Install result: ${res}`);
|
|
30
|
+
// vela 5 安装成功的日志为:
|
|
31
|
+
// onInstallResult: com.application.watch.demo(success 0)
|
|
25
32
|
if (res.includes('(success 0)')) {
|
|
26
33
|
return Promise.resolve();
|
|
27
34
|
} else {
|
|
@@ -33,8 +40,9 @@ class MiniSound5 extends _miwear.VelaMiwear5 {
|
|
|
33
40
|
* 使用 pm 卸载快应用
|
|
34
41
|
* @param packageName 快应用的包名
|
|
35
42
|
*/
|
|
36
|
-
uninstall(packageName) {
|
|
37
|
-
|
|
43
|
+
async uninstall(packageName) {
|
|
44
|
+
await this.xmsStatus.promise;
|
|
45
|
+
const res = await adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} shell pm uninstall ${packageName}`);
|
|
38
46
|
if (res.includes('(success 0)')) {
|
|
39
47
|
return Promise.resolve();
|
|
40
48
|
} else {
|
package/lib/instance/miwear.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { VelaImageType } from '../typing/Vvd';
|
|
|
5
5
|
* 针对 Vela正式版(4.0)的镜像
|
|
6
6
|
*/
|
|
7
7
|
declare class MiwearInstance extends CommonEmulatorInstance {
|
|
8
|
-
|
|
8
|
+
xmsInitedFlag: RegExp;
|
|
9
9
|
static appInstalledFlag: RegExp;
|
|
10
10
|
imageType: VelaImageType;
|
|
11
11
|
appDir: string;
|
package/lib/instance/miwear.js
CHANGED
|
@@ -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
|
-
|
|
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);
|
|
@@ -64,7 +66,7 @@ class MiwearInstance extends _common.default {
|
|
|
64
66
|
function getTimeout(size) {
|
|
65
67
|
if (!size) return 10 * 1000;
|
|
66
68
|
const mu = size / 1024 / 1024;
|
|
67
|
-
return mu < 1 ?
|
|
69
|
+
return mu < 1 ? 20 * 1000 : mu < 4 ? 60 * 1000 : 2 * 60 * 1000;
|
|
68
70
|
}
|
|
69
71
|
const timeout = getTimeout(options?.size);
|
|
70
72
|
let timer = setTimeout(() => {
|
|
@@ -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 (
|
|
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}`;
|
package/lib/instance/pre.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import CommonEmulatorInstance from './common';
|
|
|
6
6
|
declare class PreInstance extends CommonEmulatorInstance {
|
|
7
7
|
imageType: VelaImageType;
|
|
8
8
|
appDir: string;
|
|
9
|
-
|
|
9
|
+
xmsInitedFlag: RegExp;
|
|
10
10
|
install(rpkPath: string, opt: {
|
|
11
11
|
packageName: string;
|
|
12
12
|
size?: number;
|
package/lib/instance/pre.js
CHANGED
|
@@ -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
|
-
|
|
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}`;
|
package/lib/instance/vela5.d.ts
CHANGED
|
@@ -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
|
-
|
|
4
|
+
xmsInitedFlag: RegExp;
|
|
5
5
|
static appStartedFlag: RegExp;
|
|
6
6
|
imageType: VelaImageType;
|
|
7
7
|
appDir: string;
|
package/lib/instance/vela5.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
}
|
package/lib/typing/Vvd.d.ts
CHANGED
|
@@ -27,8 +27,9 @@ export interface IVvdParams {
|
|
|
27
27
|
flavor?: string;
|
|
28
28
|
density?: string;
|
|
29
29
|
customLcdRadius?: string;
|
|
30
|
-
imageType
|
|
30
|
+
imageType?: VelaImageType;
|
|
31
31
|
skinInfo?: EmulatorSkin;
|
|
32
|
+
marketName?: string;
|
|
32
33
|
}
|
|
33
34
|
export interface EmulatorPart {
|
|
34
35
|
display: {
|
|
@@ -100,7 +101,8 @@ export declare enum SDKParts {
|
|
|
100
101
|
QA = "qa",
|
|
101
102
|
SKINS = "skins",
|
|
102
103
|
SYSTEM_IMAGES = "system-images",
|
|
103
|
-
MODEM_SIMULATOR = "modem_simulator"
|
|
104
|
+
MODEM_SIMULATOR = "modem_simulator",
|
|
105
|
+
TOOLS = "tools"
|
|
104
106
|
}
|
|
105
107
|
export declare enum VELAHOME {
|
|
106
108
|
SDK = ".vela/sdk",
|
package/lib/typing/Vvd.js
CHANGED
|
@@ -23,6 +23,7 @@ let SDKParts = exports.SDKParts = /*#__PURE__*/function (SDKParts) {
|
|
|
23
23
|
SDKParts["SKINS"] = "skins";
|
|
24
24
|
SDKParts["SYSTEM_IMAGES"] = "system-images";
|
|
25
25
|
SDKParts["MODEM_SIMULATOR"] = "modem_simulator";
|
|
26
|
+
SDKParts["TOOLS"] = "tools";
|
|
26
27
|
return SDKParts;
|
|
27
28
|
}({});
|
|
28
29
|
let VELAHOME = exports.VELAHOME = /*#__PURE__*/function (VELAHOME) {
|
package/lib/vvd/grpc/index.d.ts
CHANGED
package/lib/vvd/grpc/index.js
CHANGED
|
@@ -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;
|
|
@@ -27,8 +30,6 @@ class GrpcEmulator {
|
|
|
27
30
|
defaults: true,
|
|
28
31
|
oneofs: true
|
|
29
32
|
});
|
|
30
|
-
this.deadline = new Date();
|
|
31
|
-
this.deadline.setMinutes(this.deadline.getMinutes() + 2);
|
|
32
33
|
this.controller = (0, _grpcJs.loadPackageDefinition)(packageDefinition).android.emulation.control;
|
|
33
34
|
const mateInfo = new _grpcJs.Metadata();
|
|
34
35
|
mateInfo.set(AuthorizationKey, `Bearer ${this.token}`);
|
|
@@ -49,21 +50,53 @@ class GrpcEmulator {
|
|
|
49
50
|
getAuthMeta() {
|
|
50
51
|
return this.authMate;
|
|
51
52
|
}
|
|
52
|
-
waitForReady() {
|
|
53
|
+
async waitForReady() {
|
|
53
54
|
if (this.connected) {
|
|
54
|
-
return
|
|
55
|
+
return true;
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
const channel = this.client.getChannel();
|
|
58
|
+
const curState = channel.getConnectivityState(true);
|
|
59
|
+
if (curState === _connectivityState.ConnectivityState.READY) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
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
|
|
74
|
+
|
|
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;
|
|
62
95
|
}
|
|
63
|
-
this.connected = true;
|
|
64
|
-
resolve(true);
|
|
65
96
|
});
|
|
66
|
-
}
|
|
97
|
+
};
|
|
98
|
+
watcher();
|
|
99
|
+
return promise;
|
|
67
100
|
}
|
|
68
101
|
async streamScreenshot(imageFormat) {
|
|
69
102
|
await this.waitForReady();
|
package/lib/vvd/index.d.ts
CHANGED
|
@@ -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');
|
|
@@ -368,13 +370,17 @@ class VvdManager {
|
|
|
368
370
|
let needUpdate = false;
|
|
369
371
|
|
|
370
372
|
// 检查 ramsize 调整为 1024
|
|
371
|
-
if (config['hw.ramSize'] < 1024) {
|
|
373
|
+
if (config['hw.ramSize'] && typeof config['hw.ramSize'] === 'number' && config['hw.ramSize'] < 1024) {
|
|
372
374
|
needUpdate = true;
|
|
373
375
|
config['hw.ramSize'] = 1024;
|
|
374
376
|
}
|
|
377
|
+
// 统一路径分隔符为 /
|
|
378
|
+
const normalizePath = p => p.replace(/\\/g, '/');
|
|
379
|
+
|
|
375
380
|
// 检查皮肤路径
|
|
376
|
-
|
|
377
|
-
|
|
381
|
+
const skinPath = config['skin.path'];
|
|
382
|
+
if (skinPath && normalizePath(skinPath.toString())?.includes('.export_dev/skins')) {
|
|
383
|
+
if (normalizePath(skinPath.toString())?.includes('.export_dev/skins/user')) {
|
|
378
384
|
// 自定义的皮肤,将自定义皮肤迁移到新的 sdk 目录中
|
|
379
385
|
const oldUserSkinDir = _path.default.join(_os.default.homedir(), '.export_dev/skins/user');
|
|
380
386
|
const newUserSkinDir = _path.default.join(this.sdkHome, 'skins', 'user');
|
|
@@ -394,13 +400,26 @@ class VvdManager {
|
|
|
394
400
|
}
|
|
395
401
|
}
|
|
396
402
|
needUpdate = true;
|
|
397
|
-
config['skin.path'] =
|
|
403
|
+
config['skin.path'] = normalizePath(skinPath.toString()).replace('.export_dev/skins', '.vela/sdk/skins');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 迁移 原来 user 目录中的 xiaomi_band_10
|
|
407
|
+
if (skinPath && normalizePath(skinPath.toString())?.endsWith('/user/xiaomi_band_10')) {
|
|
408
|
+
_ColorConsole.default.log('migrate user/xiaomi_band_10 to builtin/xiaomi_band_10');
|
|
409
|
+
config['skin.path'] = normalizePath(skinPath.toString()).replace('/user/xiaomi_band_10', '/builtin/xiaomi_band_10');
|
|
410
|
+
needUpdate = true;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// 检查 hw.cpu.ncore
|
|
414
|
+
if (config['hw.cpu.ncore'] && typeof config['hw.cpu.ncore'] === 'number' && config['hw.cpu.ncore'] > 2) {
|
|
415
|
+
needUpdate = true;
|
|
416
|
+
config['hw.cpu.ncore'] = 2;
|
|
398
417
|
}
|
|
399
418
|
|
|
400
419
|
// 检查镜像路径
|
|
401
|
-
if (config['image.sysdir.2']?.includes('.export_dev/system-images')) {
|
|
420
|
+
if (config['image.sysdir.2'] && normalizePath(config['image.sysdir.2'].toString())?.includes('.export_dev/system-images')) {
|
|
402
421
|
needUpdate = true;
|
|
403
|
-
config['image.sysdir.2'] = config['image.sysdir.2'].replace('.export_dev/system-images', '.vela/sdk/system-images');
|
|
422
|
+
config['image.sysdir.2'] = normalizePath(config['image.sysdir.2'].toString()).replace('.export_dev/system-images', '.vela/sdk/system-images');
|
|
404
423
|
}
|
|
405
424
|
if (needUpdate) {
|
|
406
425
|
await _promises.default.writeFile(configIni, (0, _ini.stringify)(config));
|
|
@@ -436,7 +455,7 @@ class VvdManager {
|
|
|
436
455
|
// -fsdev local,security_model=none,id=fsdev0,path=${HOST_9PFS_DIR} \
|
|
437
456
|
// -device virtio-9p-device,id=fs0,fsdev=fsdev0,mount_tag=host `
|
|
438
457
|
|
|
439
|
-
const qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
458
|
+
const qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting -smp 2`;
|
|
440
459
|
|
|
441
460
|
// qt windows 配置
|
|
442
461
|
// 在 docker,wls,等无界面平台上用 -no-window ,否则用 -qt-hide-window
|
|
@@ -513,13 +532,33 @@ class VvdManager {
|
|
|
513
532
|
const onErrout = options.stderrCallback || console.log;
|
|
514
533
|
const e = runningVvds.find(e => e['avd.name'] === vvdName);
|
|
515
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
|
+
};
|
|
516
554
|
|
|
517
555
|
// 该模拟器已经启动,则创建一个日志流返回
|
|
518
556
|
if (e) {
|
|
519
557
|
// 找出来它原来使用的 debugPort
|
|
520
558
|
const regex = /hostfwd=tcp:(.*?):(\d+)-10\.0\.2\.15:101/;
|
|
521
559
|
const debugPort = e.cmdline?.match(regex)?.[2];
|
|
522
|
-
const
|
|
560
|
+
const imageType = await getImageType(e['port.serial']);
|
|
561
|
+
const emulatorInstance = (0, _instance.findInstance)(imageType, {
|
|
523
562
|
serialPort: e['port.serial'],
|
|
524
563
|
vvdName: vvdName,
|
|
525
564
|
onStdout,
|
|
@@ -527,11 +566,16 @@ class VvdManager {
|
|
|
527
566
|
debugPort,
|
|
528
567
|
customLogger: options.customLogger
|
|
529
568
|
});
|
|
569
|
+
const velaAgent = (0, _grpc.createGrpcClient)(e);
|
|
570
|
+
await velaAgent.waitForReady();
|
|
571
|
+
emulatorInstance.xmsStatus.resolve();
|
|
530
572
|
return {
|
|
531
573
|
coldBoot: false,
|
|
532
574
|
emulatorInstance,
|
|
533
575
|
getAgent: () => (0, _grpc.createGrpcClient)(e),
|
|
534
|
-
grpcConfig: e
|
|
576
|
+
grpcConfig: e,
|
|
577
|
+
velaAgent,
|
|
578
|
+
imageType
|
|
535
579
|
};
|
|
536
580
|
}
|
|
537
581
|
|
|
@@ -540,65 +584,85 @@ class VvdManager {
|
|
|
540
584
|
const spawnArgs = cmd.split(' ');
|
|
541
585
|
const spawnBin = spawnArgs.shift();
|
|
542
586
|
logger(`Start CMD: ${cmd}`);
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
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);
|
|
579
631
|
} else {
|
|
580
|
-
|
|
632
|
+
emulatorInstance.xmsStatus.resolve();
|
|
581
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');
|
|
582
645
|
}
|
|
583
|
-
}
|
|
584
|
-
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
readlines.stdoutReadline.on('line', emulatorStartedHandler);
|
|
585
649
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
+
});
|
|
595
659
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
});
|
|
660
|
+
// 监听模拟器的错误事件
|
|
661
|
+
emulatorProcess.on('error', err => {
|
|
662
|
+
readlines.dispose();
|
|
663
|
+
reject(err);
|
|
601
664
|
});
|
|
665
|
+
return promise;
|
|
602
666
|
}
|
|
603
667
|
stopVvd(name) {
|
|
604
668
|
let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10 * 1000;
|
|
@@ -774,14 +838,17 @@ class VvdManager {
|
|
|
774
838
|
*/
|
|
775
839
|
async downloadSDK(opt) {
|
|
776
840
|
const updateList = opt.force ? Object.values(_Vvd.SDKParts) : await this.hasSDKPartUpdate();
|
|
777
|
-
let urls =
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
841
|
+
let urls = [];
|
|
842
|
+
for (const t of updateList) {
|
|
843
|
+
urls.push({
|
|
844
|
+
name: t,
|
|
845
|
+
url: await (0, _constants.getSDKPartDownloadUrl)(t)
|
|
846
|
+
});
|
|
847
|
+
}
|
|
781
848
|
if (opt.imageTypeArr) {
|
|
782
849
|
for (const imgType of opt.imageTypeArr) {
|
|
783
850
|
const needsUpdate = await this.isLocalImageNeedUpdate(imgType);
|
|
784
|
-
const downloadUrl = (0, _constants.getImageDownloadUrl)()[imgType];
|
|
851
|
+
const downloadUrl = (await (0, _constants.getImageDownloadUrl)())[imgType];
|
|
785
852
|
// 需要更新并且urls中不存在则添加
|
|
786
853
|
if (needsUpdate && urls.findIndex(u => u.url === downloadUrl) < 0) {
|
|
787
854
|
urls.push({
|
|
@@ -843,7 +910,7 @@ class VvdManager {
|
|
|
843
910
|
|
|
844
911
|
/** 下载vela系统镜像 */
|
|
845
912
|
async downloadImage(imageId, opt) {
|
|
846
|
-
const downloadUrls = (0, _constants.getImageDownloadUrl)();
|
|
913
|
+
const downloadUrls = await (0, _constants.getImageDownloadUrl)();
|
|
847
914
|
const u = downloadUrls[imageId];
|
|
848
915
|
const downloader = await (await ipull).downloadFile({
|
|
849
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.
|
|
3
|
+
"version": "2.0.6-beta.5",
|
|
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.
|
|
35
|
+
"@aiot-toolkit/shared-utils": "2.0.6-beta.5",
|
|
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": "
|
|
52
|
+
"gitHead": "d40eba7eacc8334bce1e952c39365513a171719e"
|
|
53
53
|
}
|