@aiot-toolkit/emulator 2.0.2-dev.2 → 2.0.2-dev.4
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/index.d.ts +2 -2
- package/lib/index.js +2 -3
- package/lib/instance/{goldfish.d.ts → common.d.ts} +16 -15
- package/lib/instance/{goldfish1.js → common.js} +31 -68
- package/lib/instance/dev.d.ts +15 -0
- package/lib/instance/dev.js +179 -0
- package/lib/instance/index.d.ts +7 -0
- package/lib/instance/index.js +32 -0
- package/lib/instance/miwear.d.ts +21 -0
- package/lib/instance/miwear.js +232 -0
- package/lib/instance/{goldfish1.d.ts → preDev.d.ts} +5 -23
- package/lib/instance/{goldfish.js → preDev.js} +29 -105
- package/lib/static/debugger_ip.cfg +1 -0
- package/lib/typing/Instance.d.ts +2 -0
- package/lib/utils/index.d.ts +7 -0
- package/lib/utils/index.js +49 -1
- package/package.json +4 -4
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as VelaAvdCls } from './avd';
|
|
2
|
-
|
|
2
|
+
export * from './instance';
|
|
3
3
|
export * from './typing/Avd';
|
|
4
4
|
export * from './typing/Instance';
|
|
5
|
-
export {
|
|
5
|
+
export { VelaAvdCls };
|
package/lib/index.js
CHANGED
|
@@ -17,10 +17,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.VelaAvdCls =
|
|
20
|
+
exports.VelaAvdCls = void 0;
|
|
21
21
|
const avd_1 = __importDefault(require("./avd"));
|
|
22
22
|
Object.defineProperty(exports, "VelaAvdCls", { enumerable: true, get: function () { return avd_1.default; } });
|
|
23
|
-
|
|
24
|
-
Object.defineProperty(exports, "GoldfishInstance", { enumerable: true, get: function () { return goldfish_1.default; } });
|
|
23
|
+
__exportStar(require("./instance"), exports);
|
|
25
24
|
__exportStar(require("./typing/Avd"), exports);
|
|
26
25
|
__exportStar(require("./typing/Instance"), exports);
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import IManifest from '@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/interface/IManifest';
|
|
2
3
|
import { ChildProcess } from 'child_process';
|
|
4
|
+
import VelaAvdCls from '../avd';
|
|
3
5
|
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* CommonInstance
|
|
8
|
+
*/
|
|
9
|
+
declare class CommonInstance {
|
|
10
|
+
projectPath: string;
|
|
11
|
+
sdkHome: string;
|
|
12
|
+
avdHome: string;
|
|
13
|
+
adbPort: number;
|
|
9
14
|
debugPort: number;
|
|
10
|
-
|
|
11
|
-
private velaAvdCls;
|
|
12
|
-
private packageName;
|
|
15
|
+
velaAvdCls: VelaAvdCls;
|
|
13
16
|
goldfishProcess: ChildProcess | undefined;
|
|
14
|
-
v9fsProcess: ChildProcess | undefined;
|
|
15
17
|
isFirstStart: boolean;
|
|
16
|
-
|
|
18
|
+
startOptions: IStartOptions | undefined;
|
|
19
|
+
projectInfo: IManifest;
|
|
17
20
|
constructor(params: INewGoldfishInstanceParams);
|
|
18
21
|
/** 获取模拟器二进制文件所在位置 */
|
|
19
22
|
getEmulatorBinPath(): string;
|
|
@@ -21,21 +24,19 @@ declare class GoldfishInstance {
|
|
|
21
24
|
start(options: IStartOptions): Promise<void>;
|
|
22
25
|
/** 在goldfish中启动快应用 */
|
|
23
26
|
startupQuickApp(options: IStartOptions): void;
|
|
24
|
-
/** host启动9pServer */
|
|
25
|
-
ensure9pServerRunnning(): Promise<void>;
|
|
26
27
|
/** 启动goldfish模拟器 */
|
|
27
28
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
28
29
|
/** 通过adb连接模拟器 */
|
|
29
30
|
connectGoldfish(): Promise<boolean>;
|
|
30
31
|
/** 将打包后的文件推到挂载的快应用目录 */
|
|
31
|
-
pushRpk(): void
|
|
32
|
+
pushRpk(sourceRoot: string): Promise<void>;
|
|
32
33
|
/** 杀死进程 */
|
|
33
34
|
killProcess(currProcess?: ChildProcess): void;
|
|
34
35
|
/** 停止模拟器并释放相关资源 */
|
|
35
|
-
stop(): void
|
|
36
|
+
stop(): Promise<void>;
|
|
36
37
|
/** 重启模拟器 */
|
|
37
38
|
restart(): void;
|
|
38
39
|
/** 创建server */
|
|
39
40
|
createWebsockeServer(): Promise<void>;
|
|
40
41
|
}
|
|
41
|
-
export default
|
|
42
|
+
export default CommonInstance;
|
|
@@ -39,8 +39,6 @@ const UxFileUtils_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/utils/
|
|
|
39
39
|
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
40
40
|
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
41
41
|
const child_process_1 = require("child_process");
|
|
42
|
-
const find_process_1 = __importDefault(require("find-process"));
|
|
43
|
-
const fs_1 = __importDefault(require("fs"));
|
|
44
42
|
const os_1 = __importDefault(require("os"));
|
|
45
43
|
const path_1 = __importDefault(require("path"));
|
|
46
44
|
const portfinder_1 = __importDefault(require("portfinder"));
|
|
@@ -48,11 +46,13 @@ const ws_1 = require("ws");
|
|
|
48
46
|
const avd_1 = __importDefault(require("../avd"));
|
|
49
47
|
const constants_1 = require("../static/constants");
|
|
50
48
|
const utils_1 = require("../utils");
|
|
51
|
-
|
|
49
|
+
/**
|
|
50
|
+
* CommonInstance
|
|
51
|
+
*/
|
|
52
|
+
class CommonInstance {
|
|
52
53
|
constructor(params) {
|
|
53
54
|
this.adbPort = 5555;
|
|
54
55
|
this.debugPort = 10055;
|
|
55
|
-
this.host9pPort = 7878;
|
|
56
56
|
this.isFirstStart = true;
|
|
57
57
|
this.projectPath = params.projectPath;
|
|
58
58
|
this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
|
|
@@ -61,8 +61,7 @@ class GoldfishInstance {
|
|
|
61
61
|
sdkHome: this.sdkHome,
|
|
62
62
|
avdHome: this.avdHome
|
|
63
63
|
});
|
|
64
|
-
|
|
65
|
-
this.packageName = appPackageName;
|
|
64
|
+
this.projectInfo = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
|
|
66
65
|
}
|
|
67
66
|
/** 获取模拟器二进制文件所在位置 */
|
|
68
67
|
getEmulatorBinPath() {
|
|
@@ -85,7 +84,7 @@ class GoldfishInstance {
|
|
|
85
84
|
yield this.createWebsockeServer();
|
|
86
85
|
}
|
|
87
86
|
// adb push快应用到模拟器的/data/app目录
|
|
88
|
-
this.pushRpk();
|
|
87
|
+
yield this.pushRpk(path_1.default.resolve(this.projectPath, './dist'));
|
|
89
88
|
// 在模拟器中启动快应用
|
|
90
89
|
this.startupQuickApp(options);
|
|
91
90
|
this.isFirstStart = false;
|
|
@@ -98,9 +97,9 @@ class GoldfishInstance {
|
|
|
98
97
|
/** 在goldfish中启动快应用 */
|
|
99
98
|
startupQuickApp(options) {
|
|
100
99
|
try {
|
|
101
|
-
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.
|
|
100
|
+
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.projectInfo.package} &`;
|
|
102
101
|
if (options.devtool) {
|
|
103
|
-
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.
|
|
102
|
+
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.projectInfo.package} &`;
|
|
104
103
|
}
|
|
105
104
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
106
105
|
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
@@ -110,44 +109,6 @@ class GoldfishInstance {
|
|
|
110
109
|
ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
|
-
/** host启动9pServer */
|
|
114
|
-
ensure9pServerRunnning() {
|
|
115
|
-
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
116
|
-
var _a;
|
|
117
|
-
const yaFileName = os_1.default.platform() === 'win32' ? 'ya-vm-file-server.exe' : 'ya-vm-file-server';
|
|
118
|
-
const pidList = yield (0, find_process_1.default)('name', yaFileName);
|
|
119
|
-
if (pidList.length > 0) {
|
|
120
|
-
ColorConsole_1.default.log('### Emulator ### 9p server started in host');
|
|
121
|
-
return resolve();
|
|
122
|
-
}
|
|
123
|
-
ColorConsole_1.default.log('### Emulator ### Starting 9p server in host');
|
|
124
|
-
const quickappMountDir = path_1.default.resolve(this.sdkHome, 'qa');
|
|
125
|
-
const toolsHome = path_1.default.resolve(this.sdkHome, 'tools');
|
|
126
|
-
const serverBinPath = path_1.default.resolve(toolsHome, yaFileName);
|
|
127
|
-
fs_1.default.chmodSync(serverBinPath, 0o777);
|
|
128
|
-
this.host9pPort = yield portfinder_1.default.getPortPromise({ port: 7878 });
|
|
129
|
-
const address = `127.0.0.1:${this.host9pPort}`;
|
|
130
|
-
this.v9fsProcess = (0, child_process_1.spawn)(serverBinPath, [
|
|
131
|
-
'--mount-point',
|
|
132
|
-
quickappMountDir,
|
|
133
|
-
'--network-address',
|
|
134
|
-
address,
|
|
135
|
-
'--debug'
|
|
136
|
-
]);
|
|
137
|
-
(_a = this.v9fsProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
138
|
-
const output = data.toString();
|
|
139
|
-
if (output.match(/Server started, listening on: 127.0.0.1:(\d+)/)) {
|
|
140
|
-
ColorConsole_1.default.log(output);
|
|
141
|
-
ColorConsole_1.default.log('### Emulator ### 9p server starts successfully');
|
|
142
|
-
return resolve();
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
this.v9fsProcess.on('exit', (code) => {
|
|
146
|
-
ColorConsole_1.default.error(`### Emulator ### ya-vm-file-server exited with code ${code}`);
|
|
147
|
-
return reject();
|
|
148
|
-
});
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
112
|
/** 启动goldfish模拟器 */
|
|
152
113
|
startGoldfish(options) {
|
|
153
114
|
var _a;
|
|
@@ -250,14 +211,16 @@ class GoldfishInstance {
|
|
|
250
211
|
});
|
|
251
212
|
}
|
|
252
213
|
/** 将打包后的文件推到挂载的快应用目录 */
|
|
253
|
-
pushRpk() {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
214
|
+
pushRpk(sourceRoot) {
|
|
215
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
216
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
217
|
+
const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
|
|
218
|
+
const appRunDir = '/data/app';
|
|
219
|
+
ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
|
|
220
|
+
(0, child_process_1.execSync)(`adb -s ${sn} shell mkdir ${appRunDir}/${appPackageName}`, { stdio: 'ignore' });
|
|
221
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourceRoot}/* ${appRunDir}/${appPackageName}`);
|
|
222
|
+
ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
|
|
223
|
+
});
|
|
261
224
|
}
|
|
262
225
|
/** 杀死进程 */
|
|
263
226
|
killProcess(currProcess) {
|
|
@@ -281,19 +244,19 @@ class GoldfishInstance {
|
|
|
281
244
|
}
|
|
282
245
|
/** 停止模拟器并释放相关资源 */
|
|
283
246
|
stop() {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
247
|
+
var _a;
|
|
248
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
+
if (this.goldfishProcess) {
|
|
250
|
+
// Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
|
|
251
|
+
// 这里的作用是手动删除创建出来的子进程
|
|
252
|
+
// if (os.platform() === 'linux' && this.goldfishProcess.pid) {
|
|
253
|
+
// process.kill(this.goldfishProcess.pid + 1)
|
|
254
|
+
// }
|
|
255
|
+
this.killProcess(this.goldfishProcess);
|
|
256
|
+
yield (0, utils_1.killProcessByCmd)((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.avdName);
|
|
257
|
+
this.goldfishProcess = undefined;
|
|
289
258
|
}
|
|
290
|
-
|
|
291
|
-
this.goldfishProcess = undefined;
|
|
292
|
-
}
|
|
293
|
-
if (this.v9fsProcess) {
|
|
294
|
-
this.killProcess(this.v9fsProcess);
|
|
295
|
-
this.v9fsProcess = undefined;
|
|
296
|
-
}
|
|
259
|
+
});
|
|
297
260
|
}
|
|
298
261
|
/** 重启模拟器 */
|
|
299
262
|
restart() {
|
|
@@ -329,4 +292,4 @@ class GoldfishInstance {
|
|
|
329
292
|
});
|
|
330
293
|
}
|
|
331
294
|
}
|
|
332
|
-
exports.default =
|
|
295
|
+
exports.default = CommonInstance;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
2
|
+
import CommonInstance from './common';
|
|
3
|
+
declare class GoldfishInstance extends CommonInstance {
|
|
4
|
+
private appRunDir;
|
|
5
|
+
constructor(params: INewGoldfishInstanceParams);
|
|
6
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
7
|
+
start(options: IStartOptions): Promise<void>;
|
|
8
|
+
/** 在goldfish中启动快应用 */
|
|
9
|
+
startupQuickApp(options: IStartOptions): Promise<void>;
|
|
10
|
+
/** 启动goldfish模拟器 */
|
|
11
|
+
startGoldfish(options: IStartOptions): Promise<void>;
|
|
12
|
+
/** 将打包后的文件推到挂载的快应用目录 */
|
|
13
|
+
pushRpk(sourceRoot: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export default GoldfishInstance;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
39
|
+
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
const path_1 = __importDefault(require("path"));
|
|
42
|
+
const portfinder_1 = __importDefault(require("portfinder"));
|
|
43
|
+
const constants_1 = require("../static/constants");
|
|
44
|
+
const common_1 = __importDefault(require("./common"));
|
|
45
|
+
class GoldfishInstance extends common_1.default {
|
|
46
|
+
constructor(params) {
|
|
47
|
+
super(params);
|
|
48
|
+
this.appRunDir = '/data/app';
|
|
49
|
+
}
|
|
50
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
51
|
+
start(options) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
this.startOptions = options;
|
|
54
|
+
// 启动模拟器
|
|
55
|
+
yield this.startGoldfish(options);
|
|
56
|
+
const connected = yield this.connectGoldfish();
|
|
57
|
+
if (connected) {
|
|
58
|
+
ColorConsole_1.default.log('### Emulator ### Goldfish emulator connected successfully');
|
|
59
|
+
if (this.isFirstStart && this.startOptions.serverPort) {
|
|
60
|
+
yield this.createWebsockeServer();
|
|
61
|
+
}
|
|
62
|
+
// adb push快应用到模拟器的/data/app目录
|
|
63
|
+
yield this.pushRpk(path_1.default.resolve(this.projectPath, './build'));
|
|
64
|
+
// 在模拟器中启动快应用
|
|
65
|
+
this.startupQuickApp(options);
|
|
66
|
+
this.isFirstStart = false;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** 在goldfish中启动快应用 */
|
|
74
|
+
startupQuickApp(options) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
try {
|
|
77
|
+
const { package: packageName } = this.projectInfo;
|
|
78
|
+
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${packageName} &`;
|
|
79
|
+
if (options.devtool) {
|
|
80
|
+
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
|
|
81
|
+
}
|
|
82
|
+
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
83
|
+
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
84
|
+
adbMiwt.execAdbCmdAsync(vappCmd, { stdio: 'ignore', encoding: 'utf-8' });
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** 启动goldfish模拟器 */
|
|
92
|
+
startGoldfish(options) {
|
|
93
|
+
var _a;
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const { avdName, devtool } = options;
|
|
96
|
+
const emulatorBin = this.getEmulatorBinPath();
|
|
97
|
+
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
98
|
+
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
99
|
+
const { avdArch, avdImagePath } = avdInfo;
|
|
100
|
+
this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
|
|
101
|
+
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
102
|
+
if (!avdImagePath) {
|
|
103
|
+
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
104
|
+
}
|
|
105
|
+
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
106
|
+
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
107
|
+
// 端口映射
|
|
108
|
+
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
|
|
109
|
+
if (devtool) {
|
|
110
|
+
portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
111
|
+
}
|
|
112
|
+
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
113
|
+
const systemImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/system.img');
|
|
114
|
+
const dataImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/data.img');
|
|
115
|
+
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
|
|
116
|
+
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
117
|
+
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
|
|
118
|
+
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
119
|
+
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
120
|
+
// vnc配置
|
|
121
|
+
let windowStr = '';
|
|
122
|
+
let vncStr = '';
|
|
123
|
+
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
|
|
124
|
+
windowStr = '-no-window';
|
|
125
|
+
const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
|
|
126
|
+
vncStr = `-vnc :${portSuffix}`;
|
|
127
|
+
}
|
|
128
|
+
const stdioType = options.disableNSH ? 'pipe' : 'inherit';
|
|
129
|
+
// 启动goldfish的命令和参数
|
|
130
|
+
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
|
|
131
|
+
const spawnArgs = cmd.split(' ');
|
|
132
|
+
const spawnBin = spawnArgs.shift();
|
|
133
|
+
ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
|
|
134
|
+
return new Promise((resolve) => {
|
|
135
|
+
var _a, _b;
|
|
136
|
+
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
|
|
137
|
+
if (options.disableNSH) {
|
|
138
|
+
(_a = this.goldfishProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
139
|
+
if (options.stdoutCallback) {
|
|
140
|
+
options.stdoutCallback(data);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(data.toString());
|
|
144
|
+
}
|
|
145
|
+
if (data.toString().includes('(NSH)')) {
|
|
146
|
+
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
147
|
+
resolve();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
(_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
151
|
+
console.log(data.toString());
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
157
|
+
resolve();
|
|
158
|
+
}, 2000);
|
|
159
|
+
}
|
|
160
|
+
this.goldfishProcess.on('exit', (code) => {
|
|
161
|
+
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** 将打包后的文件推到挂载的快应用目录 */
|
|
167
|
+
pushRpk(sourceRoot) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
170
|
+
const { package: appPackageName } = this.projectInfo;
|
|
171
|
+
const sourcePath = path_1.default.resolve(sourceRoot, './*');
|
|
172
|
+
ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${this.appRunDir}`);
|
|
173
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`);
|
|
174
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appRunDir}/${appPackageName}`);
|
|
175
|
+
ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${this.appRunDir} successfully`);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.default = GoldfishInstance;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { INewGoldfishInstanceParams } from '../typing/Instance';
|
|
2
|
+
import CommonInstance from './common';
|
|
3
|
+
import GoldfishInstance from './dev';
|
|
4
|
+
import MiwearInstance from "./miwear";
|
|
5
|
+
import OldGoldfishInstance from './preDev';
|
|
6
|
+
declare function findInstance(avdName: string, params: INewGoldfishInstanceParams): GoldfishInstance | MiwearInstance | OldGoldfishInstance | undefined;
|
|
7
|
+
export { CommonInstance, GoldfishInstance, MiwearInstance, OldGoldfishInstance, findInstance };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findInstance = exports.OldGoldfishInstance = exports.MiwearInstance = exports.GoldfishInstance = exports.CommonInstance = void 0;
|
|
7
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
8
|
+
const avd_1 = __importDefault(require("../avd"));
|
|
9
|
+
const common_1 = __importDefault(require("./common"));
|
|
10
|
+
exports.CommonInstance = common_1.default;
|
|
11
|
+
const dev_1 = __importDefault(require("./dev"));
|
|
12
|
+
exports.GoldfishInstance = dev_1.default;
|
|
13
|
+
const miwear_1 = __importDefault(require("./miwear"));
|
|
14
|
+
exports.MiwearInstance = miwear_1.default;
|
|
15
|
+
const preDev_1 = __importDefault(require("./preDev"));
|
|
16
|
+
exports.OldGoldfishInstance = preDev_1.default;
|
|
17
|
+
function findInstance(avdName, params) {
|
|
18
|
+
const { sdkHome, avdHome } = params;
|
|
19
|
+
const { avdImagePath } = new avd_1.default({ sdkHome, avdHome }).getVelaAvdInfo(avdName);
|
|
20
|
+
if (!avdImagePath) {
|
|
21
|
+
ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (avdImagePath.includes('release')) {
|
|
25
|
+
return new miwear_1.default(params);
|
|
26
|
+
}
|
|
27
|
+
else if (avdImagePath.match(/0\.0\.2|0\.0\.1/)) {
|
|
28
|
+
return new preDev_1.default(params);
|
|
29
|
+
}
|
|
30
|
+
return new dev_1.default(params);
|
|
31
|
+
}
|
|
32
|
+
exports.findInstance = findInstance;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
2
|
+
import CommonInstance from './common';
|
|
3
|
+
/**
|
|
4
|
+
* MiwearInstance
|
|
5
|
+
* 针对 vela4.0 的镜像
|
|
6
|
+
*/
|
|
7
|
+
declare class MiwearInstance extends CommonInstance {
|
|
8
|
+
private appPathInEmulator;
|
|
9
|
+
constructor(params: INewGoldfishInstanceParams);
|
|
10
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
11
|
+
start(options: IStartOptions): Promise<void>;
|
|
12
|
+
/** 启动goldfish模拟器 */
|
|
13
|
+
startGoldfish(options: IStartOptions): Promise<void>;
|
|
14
|
+
/** 通过adb连接模拟器 */
|
|
15
|
+
connectGoldfish(): Promise<boolean>;
|
|
16
|
+
/** 在goldfish中启动快应用 */
|
|
17
|
+
startupQuickApp(options: IStartOptions): Promise<void>;
|
|
18
|
+
/** 将快应用安装到应用列表 */
|
|
19
|
+
installRpkToAppList(rpkPath: string, targetDir: string): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export default MiwearInstance;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
const JavascriptDefaultCompileOption_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/JavascriptDefaultCompileOption"));
|
|
39
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
40
|
+
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
43
|
+
const path_1 = __importDefault(require("path"));
|
|
44
|
+
const portfinder_1 = __importDefault(require("portfinder"));
|
|
45
|
+
const constants_1 = require("../static/constants");
|
|
46
|
+
const utils_1 = require("../utils");
|
|
47
|
+
const common_1 = __importDefault(require("./common"));
|
|
48
|
+
/**
|
|
49
|
+
* MiwearInstance
|
|
50
|
+
* 针对 vela4.0 的镜像
|
|
51
|
+
*/
|
|
52
|
+
class MiwearInstance extends common_1.default {
|
|
53
|
+
constructor(params) {
|
|
54
|
+
super(params);
|
|
55
|
+
this.appPathInEmulator = '/data/quickapp/app';
|
|
56
|
+
}
|
|
57
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
58
|
+
start(options) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
this.startOptions = options;
|
|
61
|
+
// 启动模拟器
|
|
62
|
+
yield this.startGoldfish(options);
|
|
63
|
+
// adb连接模拟器
|
|
64
|
+
const connected = yield this.connectGoldfish();
|
|
65
|
+
if (connected) {
|
|
66
|
+
ColorConsole_1.default.info('### Emulator ### Goldfish emulator connected successfully');
|
|
67
|
+
this.startupQuickApp(options);
|
|
68
|
+
this.isFirstStart = false;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** 启动goldfish模拟器 */
|
|
76
|
+
startGoldfish(options) {
|
|
77
|
+
var _a;
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
const { avdName, devtool } = options;
|
|
80
|
+
const emulatorBin = this.getEmulatorBinPath();
|
|
81
|
+
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
82
|
+
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
83
|
+
const { avdArch, avdImagePath } = avdInfo;
|
|
84
|
+
this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
|
|
85
|
+
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
86
|
+
if (!avdImagePath) {
|
|
87
|
+
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
88
|
+
}
|
|
89
|
+
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
90
|
+
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
91
|
+
// 端口映射
|
|
92
|
+
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
|
|
93
|
+
if (devtool) {
|
|
94
|
+
portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
95
|
+
}
|
|
96
|
+
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
97
|
+
const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.img');
|
|
98
|
+
const dataImageBin = path_1.default.resolve(avdImagePath, 'data.img');
|
|
99
|
+
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
|
|
100
|
+
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
101
|
+
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
|
|
102
|
+
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
103
|
+
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
104
|
+
// vnc配置
|
|
105
|
+
let windowStr = '';
|
|
106
|
+
let vncStr = '';
|
|
107
|
+
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
|
|
108
|
+
windowStr = '-no-window';
|
|
109
|
+
const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
|
|
110
|
+
vncStr = `-vnc :${portSuffix}`;
|
|
111
|
+
}
|
|
112
|
+
const stdioType = options.disableNSH ? 'pipe' : 'inherit';
|
|
113
|
+
// 启动goldfish的命令和参数
|
|
114
|
+
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
|
|
115
|
+
const spawnArgs = cmd.split(' ');
|
|
116
|
+
const spawnBin = spawnArgs.shift();
|
|
117
|
+
ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
|
|
118
|
+
return new Promise((resolve) => {
|
|
119
|
+
var _a;
|
|
120
|
+
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
|
|
121
|
+
(_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
122
|
+
console.log(data.toString());
|
|
123
|
+
});
|
|
124
|
+
this.goldfishProcess.on('exit', (code) => {
|
|
125
|
+
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
126
|
+
});
|
|
127
|
+
const p1 = new Promise((resolve) => {
|
|
128
|
+
var _a, _b;
|
|
129
|
+
(_b = (_a = this.goldfishProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
130
|
+
const stdoutCb = options.stdoutCallback || console.log;
|
|
131
|
+
stdoutCb(data.toString());
|
|
132
|
+
// if (data.toString().includes('proto_on_start: on_start finished')) {
|
|
133
|
+
// ColorConsole.info(`### Emulator ### Goldfish emulator starts successfully`)
|
|
134
|
+
// resolve()
|
|
135
|
+
// }
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
const p2 = setTimeout(() => {
|
|
139
|
+
ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
|
|
140
|
+
resolve();
|
|
141
|
+
}, 8000);
|
|
142
|
+
return Promise.race([p1, p2]);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/** 通过adb连接模拟器 */
|
|
147
|
+
connectGoldfish() {
|
|
148
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
let adbConnected = false;
|
|
150
|
+
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
152
|
+
while (!adbConnected) {
|
|
153
|
+
const adbKillCmd = `adb kill-server`;
|
|
154
|
+
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
155
|
+
yield adbMiwt.execAdbCmdAsync(adbKillCmd);
|
|
156
|
+
const adbConnectCmd = `adb connect ${sn}`;
|
|
157
|
+
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
158
|
+
const str = yield adbMiwt.execAdbCmdAsync(adbConnectCmd);
|
|
159
|
+
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
160
|
+
const devices = yield adbMiwt.getAdbDevices();
|
|
161
|
+
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
162
|
+
adbConnected =
|
|
163
|
+
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
164
|
+
}
|
|
165
|
+
Promise.resolve(adbConnected);
|
|
166
|
+
});
|
|
167
|
+
yield Promise.race([
|
|
168
|
+
connectFn(),
|
|
169
|
+
new Promise((resolve) => {
|
|
170
|
+
setTimeout(() => resolve(false), 600 * 1000);
|
|
171
|
+
})
|
|
172
|
+
]);
|
|
173
|
+
return adbConnected;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/** 在goldfish中启动快应用 */
|
|
177
|
+
startupQuickApp(options) {
|
|
178
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
179
|
+
const { package: appPackageName } = this.projectInfo;
|
|
180
|
+
const releaseDir = path_1.default.resolve(this.projectPath, JavascriptDefaultCompileOption_1.default.releasePath || 'dist');
|
|
181
|
+
const files = fs_extra_1.default
|
|
182
|
+
.readdirSync(releaseDir)
|
|
183
|
+
.filter(item => item.includes(appPackageName) && item.endsWith('.rpk'));
|
|
184
|
+
if (files.length < 0) {
|
|
185
|
+
ColorConsole_1.default.error(`### Emulator the rpk does not exist`);
|
|
186
|
+
}
|
|
187
|
+
const rpkPath = path_1.default.resolve(releaseDir, files[0]);
|
|
188
|
+
// 调试模式需要push一个文件至miwear中
|
|
189
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
190
|
+
if (options.devtool) {
|
|
191
|
+
const debuggerCfgFile = path_1.default.join(__dirname, '../static/debugger_ip.cfg');
|
|
192
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell rm /data/debugger_ip.cfg`);
|
|
196
|
+
}
|
|
197
|
+
this.installRpkToAppList(rpkPath, this.appPathInEmulator);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/** 将快应用安装到应用列表 */
|
|
201
|
+
installRpkToAppList(rpkPath, targetDir) {
|
|
202
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
203
|
+
try {
|
|
204
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
205
|
+
const { package: packageName } = this.projectInfo;
|
|
206
|
+
const rpkName = path_1.default.basename(rpkPath);
|
|
207
|
+
// 1. 查询应用是否已经安装,如果安装了,则先卸载
|
|
208
|
+
const lsCmd = `adb -s ${sn} shell ls ${this.appPathInEmulator}`;
|
|
209
|
+
const res = yield adbMiwt.execAdbCmdAsync(lsCmd);
|
|
210
|
+
if (res.includes(packageName)) {
|
|
211
|
+
const uninstallCmd = `adb -s ${sn} shell pm uninstall ${packageName}`;
|
|
212
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${uninstallCmd}`);
|
|
213
|
+
adbMiwt.execAdbCmdAsync(uninstallCmd);
|
|
214
|
+
// 这里等待2s的作用是等qemu执行完uninstall操作的一系列工作
|
|
215
|
+
yield (0, utils_1.sleep)(2000);
|
|
216
|
+
}
|
|
217
|
+
// 2. adb push应用的rpk
|
|
218
|
+
const pushCmd = `adb -s ${sn} push ${rpkPath} ${targetDir}`;
|
|
219
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
|
|
220
|
+
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
221
|
+
yield (0, utils_1.sleep)(100);
|
|
222
|
+
// 3. 安装应用
|
|
223
|
+
const targetPath = `${targetDir}/${rpkName}`;
|
|
224
|
+
const installCmd = `adb -s ${sn} shell pm install ${targetPath}`;
|
|
225
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
|
|
226
|
+
adbMiwt.execAdbCmdAsync(installCmd);
|
|
227
|
+
}
|
|
228
|
+
catch (e) { }
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
exports.default = MiwearInstance;
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { ChildProcess } from 'child_process';
|
|
3
3
|
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
private sdkHome;
|
|
7
|
-
private avdHome;
|
|
8
|
-
private adbPort;
|
|
9
|
-
debugPort: number;
|
|
4
|
+
import CommonInstance from './common';
|
|
5
|
+
declare class OldGoldfishInstance extends CommonInstance {
|
|
10
6
|
private host9pPort;
|
|
11
|
-
private velaAvdCls;
|
|
12
|
-
private packageName;
|
|
13
|
-
goldfishProcess: ChildProcess | undefined;
|
|
14
7
|
v9fsProcess: ChildProcess | undefined;
|
|
15
|
-
isFirstStart: boolean;
|
|
16
|
-
private startOptions;
|
|
17
8
|
constructor(params: INewGoldfishInstanceParams);
|
|
18
|
-
/** 获取模拟器二进制文件所在位置 */
|
|
19
|
-
getEmulatorBinPath(): string;
|
|
20
9
|
/** 在goldfish模拟器中运行快应用 */
|
|
21
10
|
start(options: IStartOptions): Promise<void>;
|
|
22
11
|
/** 在goldfish中启动快应用 */
|
|
@@ -27,15 +16,8 @@ declare class GoldfishInstance {
|
|
|
27
16
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
28
17
|
/** 通过adb连接模拟器 */
|
|
29
18
|
connectGoldfish(): Promise<boolean>;
|
|
30
|
-
|
|
31
|
-
pushRpk(): void;
|
|
32
|
-
/** 杀死进程 */
|
|
33
|
-
killProcess(currProcess?: ChildProcess): void;
|
|
19
|
+
pushRpk(sourceRoot: string): Promise<void>;
|
|
34
20
|
/** 停止模拟器并释放相关资源 */
|
|
35
|
-
stop(): void
|
|
36
|
-
/** 重启模拟器 */
|
|
37
|
-
restart(): void;
|
|
38
|
-
/** 创建server */
|
|
39
|
-
createWebsockeServer(): Promise<void>;
|
|
21
|
+
stop(): Promise<void>;
|
|
40
22
|
}
|
|
41
|
-
export default
|
|
23
|
+
export default OldGoldfishInstance;
|
|
@@ -45,33 +45,12 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
45
45
|
const os_1 = __importDefault(require("os"));
|
|
46
46
|
const path_1 = __importDefault(require("path"));
|
|
47
47
|
const portfinder_1 = __importDefault(require("portfinder"));
|
|
48
|
-
const ws_1 = require("ws");
|
|
49
|
-
const avd_1 = __importDefault(require("../avd"));
|
|
50
48
|
const constants_1 = require("../static/constants");
|
|
51
|
-
const
|
|
52
|
-
class
|
|
49
|
+
const common_1 = __importDefault(require("./common"));
|
|
50
|
+
class OldGoldfishInstance extends common_1.default {
|
|
53
51
|
constructor(params) {
|
|
54
|
-
|
|
55
|
-
this.debugPort = 10055;
|
|
52
|
+
super(params);
|
|
56
53
|
this.host9pPort = 7878;
|
|
57
|
-
this.isFirstStart = true;
|
|
58
|
-
this.projectPath = params.projectPath;
|
|
59
|
-
this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
|
|
60
|
-
this.avdHome = params.avdHome || constants_1.defaultAvdHome;
|
|
61
|
-
this.velaAvdCls = new avd_1.default({
|
|
62
|
-
sdkHome: this.sdkHome,
|
|
63
|
-
avdHome: this.avdHome
|
|
64
|
-
});
|
|
65
|
-
const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
|
|
66
|
-
this.packageName = appPackageName;
|
|
67
|
-
}
|
|
68
|
-
/** 获取模拟器二进制文件所在位置 */
|
|
69
|
-
getEmulatorBinPath() {
|
|
70
|
-
const osPlatform = os_1.default.platform();
|
|
71
|
-
const arch = (0, utils_1.getSystemArch)();
|
|
72
|
-
const platform = osPlatform === 'win32' ? 'windows' : osPlatform;
|
|
73
|
-
const emulatorHome = path_1.default.resolve(this.sdkHome, 'emulator');
|
|
74
|
-
return path_1.default.resolve(emulatorHome, `${platform}-${arch}`, 'emulator');
|
|
75
54
|
}
|
|
76
55
|
/** 在goldfish模拟器中运行快应用 */
|
|
77
56
|
start(options) {
|
|
@@ -80,7 +59,7 @@ class GoldfishInstance {
|
|
|
80
59
|
yield this.ensure9pServerRunnning();
|
|
81
60
|
this.startOptions = options;
|
|
82
61
|
// 将rpk推到host的QuickappHome目录
|
|
83
|
-
this.pushRpk();
|
|
62
|
+
this.pushRpk(path_1.default.resolve(this.projectPath, './build'));
|
|
84
63
|
// 启动模拟器
|
|
85
64
|
yield this.startGoldfish(options);
|
|
86
65
|
const connected = yield this.connectGoldfish();
|
|
@@ -101,13 +80,14 @@ class GoldfishInstance {
|
|
|
101
80
|
/** 在goldfish中启动快应用 */
|
|
102
81
|
startupQuickApp(options) {
|
|
103
82
|
try {
|
|
83
|
+
const { package: packageName } = this.projectInfo;
|
|
104
84
|
const appMountDir = path_1.default.resolve(this.sdkHome, 'qa');
|
|
105
85
|
const mountCmd = `adb -s 127.0.0.1:${this.adbPort} shell mount -t v9fs -o tag=10.0.2.2,port=${this.host9pPort},aname=${appMountDir} /data`;
|
|
106
86
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${mountCmd}`);
|
|
107
87
|
adbMiwt.execAdbCmdSync(mountCmd);
|
|
108
|
-
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${
|
|
88
|
+
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${packageName} &`;
|
|
109
89
|
if (options.devtool) {
|
|
110
|
-
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${
|
|
90
|
+
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
|
|
111
91
|
}
|
|
112
92
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
113
93
|
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
@@ -157,7 +137,6 @@ class GoldfishInstance {
|
|
|
157
137
|
}
|
|
158
138
|
/** 启动goldfish模拟器 */
|
|
159
139
|
startGoldfish(options) {
|
|
160
|
-
var _a;
|
|
161
140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
162
141
|
const { avdName, devtool } = options;
|
|
163
142
|
const emulatorBin = this.getEmulatorBinPath();
|
|
@@ -182,9 +161,9 @@ class GoldfishInstance {
|
|
|
182
161
|
// vnc配置
|
|
183
162
|
let noWindow = false;
|
|
184
163
|
let vncStr = '';
|
|
185
|
-
if (
|
|
164
|
+
if (options.vncPort) {
|
|
186
165
|
noWindow = true;
|
|
187
|
-
const portSuffix =
|
|
166
|
+
const portSuffix = options.vncPort - constants_1.defaultVncPort;
|
|
188
167
|
vncStr = `-vnc :${portSuffix}`;
|
|
189
168
|
}
|
|
190
169
|
// 启动goldfish的命令和参数
|
|
@@ -219,7 +198,8 @@ class GoldfishInstance {
|
|
|
219
198
|
const p1 = new Promise((resolve) => {
|
|
220
199
|
var _a, _b;
|
|
221
200
|
(_b = (_a = this.goldfishProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
222
|
-
console.log
|
|
201
|
+
const stdoutCb = options.stdoutCallback || console.log;
|
|
202
|
+
stdoutCb(data.toString());
|
|
223
203
|
if (data.toString().includes('(NSH)')) {
|
|
224
204
|
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
225
205
|
resolve();
|
|
@@ -264,84 +244,28 @@ class GoldfishInstance {
|
|
|
264
244
|
return adbConnected;
|
|
265
245
|
});
|
|
266
246
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
/** 杀死进程 */
|
|
278
|
-
killProcess(currProcess) {
|
|
279
|
-
if (currProcess && currProcess.pid && currProcess.exitCode === null) {
|
|
280
|
-
console.log('process pid:', currProcess.pid);
|
|
281
|
-
try {
|
|
282
|
-
if (os_1.default.platform() === 'win32') {
|
|
283
|
-
(0, child_process_1.execSync)(`taskkill /pid ${currProcess.pid} /T /F`);
|
|
284
|
-
}
|
|
285
|
-
else if (os_1.default.platform() === 'darwin') {
|
|
286
|
-
process.kill(currProcess.pid);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
currProcess.kill();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
catch (err) {
|
|
293
|
-
ColorConsole_1.default.log(`### Emulator ### kill process get error :\n${err.stack}`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
247
|
+
pushRpk(sourceRoot) {
|
|
248
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
+
const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
|
|
250
|
+
const appRunDir = path_1.default.resolve(this.sdkHome, 'qa/app', appPackageName);
|
|
251
|
+
ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
|
|
252
|
+
fs_1.default.rmSync(appRunDir, { recursive: true, force: true });
|
|
253
|
+
FileUtil_1.default.copyFiles(sourceRoot, appRunDir);
|
|
254
|
+
ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
|
|
255
|
+
});
|
|
296
256
|
}
|
|
297
257
|
/** 停止模拟器并释放相关资源 */
|
|
298
258
|
stop() {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (os_1.default.platform() === 'linux' && this.goldfishProcess.pid) {
|
|
303
|
-
process.kill(this.goldfishProcess.pid + 1);
|
|
304
|
-
}
|
|
305
|
-
this.killProcess(this.goldfishProcess);
|
|
306
|
-
this.goldfishProcess = undefined;
|
|
307
|
-
}
|
|
308
|
-
if (this.v9fsProcess) {
|
|
309
|
-
this.killProcess(this.v9fsProcess);
|
|
310
|
-
this.v9fsProcess = undefined;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
/** 重启模拟器 */
|
|
314
|
-
restart() {
|
|
315
|
-
if (this.goldfishProcess) {
|
|
316
|
-
this.killProcess(this.goldfishProcess);
|
|
317
|
-
this.goldfishProcess = undefined;
|
|
318
|
-
}
|
|
319
|
-
this.start(this.startOptions);
|
|
320
|
-
}
|
|
321
|
-
/** 创建server */
|
|
322
|
-
createWebsockeServer() {
|
|
323
|
-
var _a;
|
|
259
|
+
const _super = Object.create(null, {
|
|
260
|
+
stop: { get: () => super.stop }
|
|
261
|
+
});
|
|
324
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
socket.on('error', err => {
|
|
331
|
-
ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
|
|
332
|
-
});
|
|
333
|
-
socket.on('message', data => {
|
|
334
|
-
const message = JSON.parse(data.toString());
|
|
335
|
-
ColorConsole_1.default.log(`### App Socket server ### Websocket server get data: ${data}`);
|
|
336
|
-
if (message.type === 'restart') {
|
|
337
|
-
this.restart();
|
|
338
|
-
}
|
|
339
|
-
else if (message.type === 'stop') {
|
|
340
|
-
this.stop();
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
});
|
|
263
|
+
_super.stop.call(this);
|
|
264
|
+
if (this.v9fsProcess) {
|
|
265
|
+
this.killProcess(this.v9fsProcess);
|
|
266
|
+
this.v9fsProcess = undefined;
|
|
267
|
+
}
|
|
344
268
|
});
|
|
345
269
|
}
|
|
346
270
|
}
|
|
347
|
-
exports.default =
|
|
271
|
+
exports.default = OldGoldfishInstance;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
10.0.2.15:101
|
package/lib/typing/Instance.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { IAvdResourcePaths } from "./Avd";
|
|
2
3
|
export interface INewGoldfishInstanceParams extends IAvdResourcePaths {
|
|
3
4
|
projectPath: string;
|
|
@@ -9,4 +10,5 @@ export interface IStartOptions {
|
|
|
9
10
|
disableNSH?: boolean;
|
|
10
11
|
serverPort?: number;
|
|
11
12
|
vncPort?: number;
|
|
13
|
+
stdoutCallback?: (buffer: Buffer) => void;
|
|
12
14
|
}
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -3,3 +3,10 @@
|
|
|
3
3
|
* 所以15.0.0之前无法通过os.arch()区分,也无法通过execSync('uname -m')区分
|
|
4
4
|
*/
|
|
5
5
|
export declare function getSystemArch(): string | void;
|
|
6
|
+
/** 根据PID杀死进程 */
|
|
7
|
+
export declare function killProcessByPid(pid: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* 根据命令杀死进程
|
|
10
|
+
*/
|
|
11
|
+
export declare function killProcessByCmd(cmd: string): Promise<void>;
|
|
12
|
+
export declare function sleep(time: number): Promise<void>;
|
package/lib/utils/index.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
5
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getSystemArch = void 0;
|
|
15
|
+
exports.sleep = exports.killProcessByCmd = exports.killProcessByPid = exports.getSystemArch = void 0;
|
|
7
16
|
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
8
17
|
const child_process_1 = require("child_process");
|
|
18
|
+
const find_process_1 = __importDefault(require("find-process"));
|
|
9
19
|
const os_1 = __importDefault(require("os"));
|
|
10
20
|
const semver_1 = __importDefault(require("semver"));
|
|
11
21
|
const cpuArch = {
|
|
@@ -37,3 +47,41 @@ function getSystemArch() {
|
|
|
37
47
|
return cpuArch[osArch];
|
|
38
48
|
}
|
|
39
49
|
exports.getSystemArch = getSystemArch;
|
|
50
|
+
/** 根据PID杀死进程 */
|
|
51
|
+
function killProcessByPid(pid) {
|
|
52
|
+
try {
|
|
53
|
+
const cmd = os_1.default.platform() === "win32"
|
|
54
|
+
? `taskkill /pid ${pid} /T /F`
|
|
55
|
+
: `kill -9 ${pid}`;
|
|
56
|
+
(0, child_process_1.execSync)(cmd);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.error(`kill process ${pid} get error: ${e}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.killProcessByPid = killProcessByPid;
|
|
63
|
+
/**
|
|
64
|
+
* 根据命令杀死进程
|
|
65
|
+
*/
|
|
66
|
+
function killProcessByCmd(cmd) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
if (!cmd)
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
const list = yield (0, find_process_1.default)('name', cmd);
|
|
72
|
+
list.forEach((item) => __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
killProcessByPid(item.pid.toString());
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
console.error(`kill process ${cmd} get error: ${e}`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
exports.killProcessByCmd = killProcessByCmd;
|
|
82
|
+
function sleep(time) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
return new Promise(resolve => setTimeout(resolve, time));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
exports.sleep = sleep;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/emulator",
|
|
3
|
-
"version": "2.0.2-dev.
|
|
3
|
+
"version": "2.0.2-dev.4",
|
|
4
4
|
"description": "vela emulator tool.",
|
|
5
5
|
"homepage": "",
|
|
6
6
|
"license": "ISC",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"emulator"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@aiot-toolkit/aiotpack": "2.0.2-dev.
|
|
39
|
-
"@aiot-toolkit/shared-utils": "2.0.2-dev.
|
|
38
|
+
"@aiot-toolkit/aiotpack": "2.0.2-dev.4",
|
|
39
|
+
"@aiot-toolkit/shared-utils": "2.0.2-dev.4",
|
|
40
40
|
"find-process": "^1.4.7",
|
|
41
41
|
"portfinder": "^1.0.32"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "534fdc7c6f018623c05499bf9add8db813ef8660"
|
|
44
44
|
}
|