@aiot-toolkit/emulator 2.0.5-beta.2 → 2.0.5-beta.21
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/README.md +79 -46
- package/lib/emulatorutil/constants.js +11 -4
- package/lib/emulatorutil/running.js +11 -3
- package/lib/instance/common.d.ts +3 -1
- package/lib/instance/common.js +8 -7
- package/lib/instance/index.d.ts +2 -1
- package/lib/instance/index.js +3 -1
- package/lib/instance/minisound.d.ts +18 -0
- package/lib/instance/minisound.js +45 -0
- package/lib/instance/miwear.d.ts +1 -0
- package/lib/instance/miwear.js +16 -1
- package/lib/instance/miwear5.d.ts +3 -0
- package/lib/instance/miwear5.js +3 -0
- package/lib/instance/vela5.js +1 -1
- package/lib/shared/index.js +1 -1
- package/lib/static/avdConfigIni.json +9 -2
- package/lib/static/proto/README.MD +2 -0
- package/lib/static/proto/emulator_controller.proto +1321 -0
- package/lib/static/proto/rtc_service.proto +117 -0
- package/lib/typing/Vvd.d.ts +2 -1
- package/lib/typing/Vvd.js +2 -1
- package/lib/vvd/grpc/grpcError.d.ts +1 -0
- package/lib/vvd/grpc/grpcError.js +10 -0
- package/lib/vvd/grpc/index.d.ts +27 -0
- package/lib/vvd/grpc/index.js +117 -0
- package/lib/vvd/grpc/types/GrpcClient.d.ts +4 -0
- package/lib/vvd/grpc/types/GrpcClient.js +5 -0
- package/lib/vvd/grpc/types/KeyEvent.d.ts +19 -0
- package/lib/vvd/grpc/types/KeyEvent.js +20 -0
- package/lib/vvd/grpc/types/MouseEvent.d.ts +30 -0
- package/lib/vvd/grpc/types/MouseEvent.js +5 -0
- package/lib/vvd/index.d.ts +4 -0
- package/lib/vvd/index.js +25 -12
- package/lib/vvd/logcat.js +3 -0
- package/package.json +6 -4
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Copyright (C) 2018 The Android Open Source Project
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
// Note that if you add/remove methods in this file you must update
|
|
16
|
+
// the metrics sql as well by running ./android/scripts/gen-grpc-sql.py
|
|
17
|
+
//
|
|
18
|
+
// Please group deleted methods in a block including the date (MM/DD/YY)
|
|
19
|
+
// it was removed. This enables us to easily keep metrics around after removal
|
|
20
|
+
//
|
|
21
|
+
// List of deleted methods
|
|
22
|
+
// rpc iWasDeleted (03/12/12)
|
|
23
|
+
// ...
|
|
24
|
+
syntax = "proto3";
|
|
25
|
+
|
|
26
|
+
option java_multiple_files = true;
|
|
27
|
+
option java_package = "com.android.emulator.control";
|
|
28
|
+
option objc_class_prefix = "AEC";
|
|
29
|
+
|
|
30
|
+
package android.emulation.control;
|
|
31
|
+
import "google/protobuf/empty.proto";
|
|
32
|
+
|
|
33
|
+
// An RTC service lets you interact with the emulator through WebRTC
|
|
34
|
+
// Note that this is currently an experimental feature, and that the
|
|
35
|
+
// service definition might change without notice. Use at your own risk!
|
|
36
|
+
//
|
|
37
|
+
// The following endpoints are needed to establish the webrtc protocol
|
|
38
|
+
// Due to limitiations in Javascript we cannot make use of bidirectional
|
|
39
|
+
// endpoints See this [blog](https://grpc.io/blog/state-of-grpc-web) for
|
|
40
|
+
// details.
|
|
41
|
+
service Rtc {
|
|
42
|
+
// This function will generate a new identifier that the client
|
|
43
|
+
// should use for further interaction. It will initiate the
|
|
44
|
+
// JSEP protocol on the server side.
|
|
45
|
+
rpc requestRtcStream(google.protobuf.Empty) returns (RtcId) {}
|
|
46
|
+
|
|
47
|
+
// Sends the given JsepMsg to the server. The RtcId in the
|
|
48
|
+
// message should point to an active stream negotiation in
|
|
49
|
+
// progress, otherwise the message will be ignored.
|
|
50
|
+
rpc sendJsepMessage(JsepMsg) returns (google.protobuf.Empty) {}
|
|
51
|
+
|
|
52
|
+
// Reads an available jsep messages for the given client id,
|
|
53
|
+
// blocking until one becomes available. Do not use the polling version
|
|
54
|
+
// above if you opt for this one.
|
|
55
|
+
//
|
|
56
|
+
// The ice candidates for example will trickle in on this callback,
|
|
57
|
+
// as will the SDP negotation.
|
|
58
|
+
rpc receiveJsepMessages(RtcId) returns (stream JsepMsg) {}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// [DEPRECATED] This is only here as the go grpc webproxy used
|
|
62
|
+
// by fuchsia does not support server side streaming. This method
|
|
63
|
+
// will be removed in the future and should not be relied upon.
|
|
64
|
+
//
|
|
65
|
+
// Reads an available jsep messages for the given client id,
|
|
66
|
+
// blocking until one becomes available. Do not use the polling version
|
|
67
|
+
// above if you opt for this one.
|
|
68
|
+
//
|
|
69
|
+
// The ice candidates for example will trickle in on this callback,
|
|
70
|
+
// as will the SDP negotation.
|
|
71
|
+
rpc receiveJsepMessage(RtcId) returns (JsepMsg) {}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
message RtcId {
|
|
75
|
+
// The unique identifier of this connection. You will have to use the
|
|
76
|
+
// same identifier when sending/receiving messages. The server will
|
|
77
|
+
// generate a guid when receiving the start message.
|
|
78
|
+
string guid = 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
message JsepMsg {
|
|
82
|
+
// The unique identifier of this connection. You will have to use the
|
|
83
|
+
// same identifier when sending/receiving messages. The server will
|
|
84
|
+
// generate a guid when receiving the start message.
|
|
85
|
+
RtcId id = 1;
|
|
86
|
+
// The JSON payload. This usually can be directly handled by the
|
|
87
|
+
// Javascript library.
|
|
88
|
+
//
|
|
89
|
+
// The dictionary can contain the following properties
|
|
90
|
+
//
|
|
91
|
+
// - bye:
|
|
92
|
+
// You can hang up now. No new message expected for you.
|
|
93
|
+
// The server has stopped the RTC stream.
|
|
94
|
+
//
|
|
95
|
+
// - start:
|
|
96
|
+
// An RTCConfiguration dictionary providing options to
|
|
97
|
+
// configure the new connection. This can include the
|
|
98
|
+
// turn configuration the serve is using. This dictionary can be
|
|
99
|
+
// passed in directly to the
|
|
100
|
+
// [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection)
|
|
101
|
+
// object.
|
|
102
|
+
//
|
|
103
|
+
// - candidate:
|
|
104
|
+
// The WebRTC API's RTCIceCandidateInit dictionary, which
|
|
105
|
+
// contains the information needed to fundamentally describe an
|
|
106
|
+
// RTCIceCandidate. See
|
|
107
|
+
// [RTCIceCandidate](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate)
|
|
108
|
+
// and [Session
|
|
109
|
+
// Lifetime](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Session_lifetime)
|
|
110
|
+
// for more details.
|
|
111
|
+
//
|
|
112
|
+
// - sdp:
|
|
113
|
+
// RTCSessionDescriptionInit dictionary containing the values
|
|
114
|
+
// to that can be assigned to a
|
|
115
|
+
// [RTCSessionDescription](https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription)
|
|
116
|
+
string message = 2;
|
|
117
|
+
}
|
package/lib/typing/Vvd.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare enum IVvdArchType {
|
|
|
8
8
|
arm64 = "arm64"
|
|
9
9
|
}
|
|
10
10
|
export declare enum VelaImageType {
|
|
11
|
+
VELA_MIWEAR_MINISOUND_5 = "vela-miwear-minisound-5.0",
|
|
11
12
|
VELA_MIWEAR_WATCH_5 = "vela-miwear-watch-5.0",
|
|
12
13
|
VELA_WATCH_5 = "vela-watch-5.0",
|
|
13
14
|
REL = "vela-release-4.0",
|
|
@@ -102,7 +103,7 @@ export declare enum SDKParts {
|
|
|
102
103
|
MODEM_SIMULATOR = "modem_simulator"
|
|
103
104
|
}
|
|
104
105
|
export declare enum VELAHOME {
|
|
105
|
-
SDK = ".
|
|
106
|
+
SDK = ".vela/sdk",
|
|
106
107
|
VVD = ".vela/vvd"
|
|
107
108
|
}
|
|
108
109
|
export type SDKDownloadOpt = {
|
package/lib/typing/Vvd.js
CHANGED
|
@@ -10,6 +10,7 @@ let IVvdArchType = exports.IVvdArchType = /*#__PURE__*/function (IVvdArchType) {
|
|
|
10
10
|
return IVvdArchType;
|
|
11
11
|
}({});
|
|
12
12
|
let VelaImageType = exports.VelaImageType = /*#__PURE__*/function (VelaImageType) {
|
|
13
|
+
VelaImageType["VELA_MIWEAR_MINISOUND_5"] = "vela-miwear-minisound-5.0";
|
|
13
14
|
VelaImageType["VELA_MIWEAR_WATCH_5"] = "vela-miwear-watch-5.0";
|
|
14
15
|
VelaImageType["VELA_WATCH_5"] = "vela-watch-5.0";
|
|
15
16
|
VelaImageType["REL"] = "vela-release-4.0";
|
|
@@ -26,7 +27,7 @@ let SDKParts = exports.SDKParts = /*#__PURE__*/function (SDKParts) {
|
|
|
26
27
|
return SDKParts;
|
|
27
28
|
}({});
|
|
28
29
|
let VELAHOME = exports.VELAHOME = /*#__PURE__*/function (VELAHOME) {
|
|
29
|
-
VELAHOME["SDK"] = ".
|
|
30
|
+
VELAHOME["SDK"] = ".vela/sdk";
|
|
30
31
|
VELAHOME["VVD"] = ".vela/vvd";
|
|
31
32
|
return VELAHOME;
|
|
32
33
|
}({});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleGrpcErrorMsg(err: Error | string): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
import { MouseEvent } from './types/MouseEvent';
|
|
3
|
+
import { GrpcKeyboardEvent } from './types/KeyEvent';
|
|
4
|
+
import { GrpcClient } from './types/GrpcClient';
|
|
5
|
+
import { EmulatorConfig } from '../../emulatorutil/running';
|
|
6
|
+
import { Metadata } from '@grpc/grpc-js';
|
|
7
|
+
export default class GrpcEmulator {
|
|
8
|
+
eConf: EmulatorConfig;
|
|
9
|
+
protoPath: string;
|
|
10
|
+
client: GrpcClient;
|
|
11
|
+
connected: boolean;
|
|
12
|
+
token: string;
|
|
13
|
+
authMate: Metadata;
|
|
14
|
+
deadline: Date;
|
|
15
|
+
controller: any;
|
|
16
|
+
screenshotStream?: Readable;
|
|
17
|
+
constructor(eConf: EmulatorConfig, protoPath: string);
|
|
18
|
+
close(): void;
|
|
19
|
+
getAuthMeta(): Metadata;
|
|
20
|
+
waitForReady(): Promise<boolean>;
|
|
21
|
+
startStream(onStreamScreenshot: (buffer: Buffer) => void): Promise<void>;
|
|
22
|
+
getScreenshot(): Promise<Buffer>;
|
|
23
|
+
getStatus(): Promise<unknown>;
|
|
24
|
+
sendMouse(message: MouseEvent): void;
|
|
25
|
+
sendKey(data: GrpcKeyboardEvent): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function createGrpcClient(eConf: EmulatorConfig): GrpcEmulator;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createGrpcClient = createGrpcClient;
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
|
9
|
+
var _protoLoader = require("@grpc/proto-loader");
|
|
10
|
+
var _grpcError = require("./grpcError");
|
|
11
|
+
var _grpcJs = require("@grpc/grpc-js");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
class GrpcEmulator {
|
|
14
|
+
connected = false;
|
|
15
|
+
constructor(eConf, protoPath) {
|
|
16
|
+
this.eConf = eConf;
|
|
17
|
+
this.protoPath = protoPath;
|
|
18
|
+
this.token = eConf['grpc.token'];
|
|
19
|
+
const packageDefinition = (0, _protoLoader.loadSync)(this.protoPath, {
|
|
20
|
+
keepCase: true,
|
|
21
|
+
longs: String,
|
|
22
|
+
enums: String,
|
|
23
|
+
defaults: true,
|
|
24
|
+
oneofs: true
|
|
25
|
+
});
|
|
26
|
+
this.deadline = new Date();
|
|
27
|
+
this.deadline.setMinutes(this.deadline.getMinutes() + 2);
|
|
28
|
+
this.controller = (0, _grpcJs.loadPackageDefinition)(packageDefinition).android.emulation.control;
|
|
29
|
+
const mateInfo = new _grpcJs.Metadata();
|
|
30
|
+
mateInfo.set('Authorization', `Bearer ${this.token}`);
|
|
31
|
+
this.authMate = mateInfo;
|
|
32
|
+
this.client = new this.controller.EmulatorController(`127.0.0.1:${eConf['grpc.port']}`, _grpcJs.credentials.createInsecure());
|
|
33
|
+
}
|
|
34
|
+
close() {
|
|
35
|
+
this.client.close();
|
|
36
|
+
}
|
|
37
|
+
getAuthMeta() {
|
|
38
|
+
const token = this.eConf['grpc.token'];
|
|
39
|
+
const mateInfo = new _grpcJs.Metadata();
|
|
40
|
+
mateInfo.set('Authorization', `Bearer ${token}`);
|
|
41
|
+
return mateInfo;
|
|
42
|
+
}
|
|
43
|
+
waitForReady() {
|
|
44
|
+
if (this.connected) {
|
|
45
|
+
return Promise.resolve(true);
|
|
46
|
+
}
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
this.client.waitForReady(this.deadline, err => {
|
|
49
|
+
if (err) {
|
|
50
|
+
this.connected = false;
|
|
51
|
+
console.error(err);
|
|
52
|
+
return reject(err);
|
|
53
|
+
}
|
|
54
|
+
this.connected = true;
|
|
55
|
+
resolve(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async startStream(onStreamScreenshot) {
|
|
60
|
+
await this.waitForReady();
|
|
61
|
+
if (this.screenshotStream) {
|
|
62
|
+
this.screenshotStream.destroy();
|
|
63
|
+
}
|
|
64
|
+
this.screenshotStream = this.client.streamScreenshot(this.controller.Image, this.authMate);
|
|
65
|
+
this.screenshotStream.on('data', response => {
|
|
66
|
+
onStreamScreenshot(response.image);
|
|
67
|
+
});
|
|
68
|
+
this.screenshotStream.on('error', err => {
|
|
69
|
+
console.error(err.message);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
getScreenshot() {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
this.client.getScreenshot(this.controller.Image, this.authMate, (err, response) => {
|
|
75
|
+
if (err) {
|
|
76
|
+
reject(err);
|
|
77
|
+
}
|
|
78
|
+
resolve(response.image);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
getStatus() {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
this.client.getStatus(this.controller.EmulatorStatus, this.authMate, (err, response) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
console.error(err);
|
|
87
|
+
(0, _grpcError.handleGrpcErrorMsg)(err);
|
|
88
|
+
return reject(err);
|
|
89
|
+
}
|
|
90
|
+
response.hardwareConfig = Object.fromEntries(response.hardwareConfig.entry.map(t => [t.key, t.value]));
|
|
91
|
+
return resolve(response);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
sendMouse(message) {
|
|
96
|
+
if (!this.connected) return;
|
|
97
|
+
const e = {
|
|
98
|
+
x: message.x,
|
|
99
|
+
y: message.y,
|
|
100
|
+
buttons: message.buttons
|
|
101
|
+
};
|
|
102
|
+
this.client.sendMouse(e, this.authMate, err => {
|
|
103
|
+
if (err) console.error(err);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
sendKey(data) {
|
|
107
|
+
if (!this.connected) return;
|
|
108
|
+
this.client.sendKey(data, this.authMate, err => {
|
|
109
|
+
if (err) console.error(err);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.default = GrpcEmulator;
|
|
114
|
+
function createGrpcClient(eConf) {
|
|
115
|
+
const protoPath = _path.default.join(__dirname, '../../static/proto/emulator_controller.proto');
|
|
116
|
+
return new GrpcEmulator(eConf, protoPath);
|
|
117
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum KeyEventType {
|
|
2
|
+
KEYDOWN = 0,
|
|
3
|
+
KEYUP = 1,
|
|
4
|
+
KEYPRESS = 2
|
|
5
|
+
}
|
|
6
|
+
export declare enum KeyCodeType {
|
|
7
|
+
USB = 0,
|
|
8
|
+
EVDEV = 1,
|
|
9
|
+
XKB = 2,
|
|
10
|
+
WIN = 3,
|
|
11
|
+
MAC = 4
|
|
12
|
+
}
|
|
13
|
+
export interface GrpcKeyboardEvent {
|
|
14
|
+
codeType?: KeyCodeType;
|
|
15
|
+
eventType?: KeyEventType;
|
|
16
|
+
keyCode?: number | string;
|
|
17
|
+
key?: string;
|
|
18
|
+
text?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.KeyEventType = exports.KeyCodeType = void 0;
|
|
7
|
+
let KeyEventType = exports.KeyEventType = /*#__PURE__*/function (KeyEventType) {
|
|
8
|
+
KeyEventType[KeyEventType["KEYDOWN"] = 0] = "KEYDOWN";
|
|
9
|
+
KeyEventType[KeyEventType["KEYUP"] = 1] = "KEYUP";
|
|
10
|
+
KeyEventType[KeyEventType["KEYPRESS"] = 2] = "KEYPRESS";
|
|
11
|
+
return KeyEventType;
|
|
12
|
+
}({});
|
|
13
|
+
let KeyCodeType = exports.KeyCodeType = /*#__PURE__*/function (KeyCodeType) {
|
|
14
|
+
KeyCodeType[KeyCodeType["USB"] = 0] = "USB";
|
|
15
|
+
KeyCodeType[KeyCodeType["EVDEV"] = 1] = "EVDEV";
|
|
16
|
+
KeyCodeType[KeyCodeType["XKB"] = 2] = "XKB";
|
|
17
|
+
KeyCodeType[KeyCodeType["WIN"] = 3] = "WIN";
|
|
18
|
+
KeyCodeType[KeyCodeType["MAC"] = 4] = "MAC";
|
|
19
|
+
return KeyCodeType;
|
|
20
|
+
}({});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface MouseEvent {
|
|
2
|
+
/**
|
|
3
|
+
* The horizontal coordinate. This is the physical location on the
|
|
4
|
+
* screen For example 0 indicates the leftmost coordinate.
|
|
5
|
+
*/
|
|
6
|
+
x?: number;
|
|
7
|
+
/**
|
|
8
|
+
* The vertical coordinate. This is the physical location on the screen
|
|
9
|
+
* For example 0 indicates the top left coordinate.
|
|
10
|
+
*/
|
|
11
|
+
y?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Indicates which buttons are pressed.
|
|
14
|
+
* 0: No button was pressed
|
|
15
|
+
* 1: Primary button (left)
|
|
16
|
+
* 2: Secondary button (right)
|
|
17
|
+
*/
|
|
18
|
+
buttons?: number;
|
|
19
|
+
/**
|
|
20
|
+
* The display device where the mouse event occurred.
|
|
21
|
+
* Omitting or using the value 0 indicates the main display.
|
|
22
|
+
*/
|
|
23
|
+
display?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface MouseEventOutput {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
buttons: number;
|
|
29
|
+
display: number;
|
|
30
|
+
}
|
package/lib/vvd/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { IVvdParams, IVvdResourcePaths, SDKParts, SDKDownloadOpt, SkinInfo, VelaImageType } from '../typing/Vvd';
|
|
2
2
|
import { IStartOptions, IStartWithSerialPort } from '../typing/Instance';
|
|
3
|
+
import { EmulatorConfig } from '../emulatorutil';
|
|
3
4
|
import { findInstance } from '../instance';
|
|
4
5
|
import type { DownloadFileOptions } from 'ipull';
|
|
6
|
+
import GrpcEmulator from './grpc';
|
|
5
7
|
export declare class VvdManager {
|
|
6
8
|
private vvdHome;
|
|
7
9
|
private sdkHome;
|
|
@@ -52,6 +54,8 @@ export declare class VvdManager {
|
|
|
52
54
|
startVvd(options: IStartOptions | IStartWithSerialPort): Promise<{
|
|
53
55
|
coldBoot: boolean;
|
|
54
56
|
emulatorInstance: ReturnType<typeof findInstance>;
|
|
57
|
+
getAgent: () => GrpcEmulator;
|
|
58
|
+
grpcConfig: EmulatorConfig;
|
|
55
59
|
}>;
|
|
56
60
|
stopVvd(name: string, timeout?: number): Promise<void>;
|
|
57
61
|
/** 获取模拟器平台的名称,darwin-aarch64 linux-aarch64 windows-x86_64等 */
|
package/lib/vvd/index.js
CHANGED
|
@@ -25,6 +25,7 @@ var _instance = require("../instance");
|
|
|
25
25
|
var _logcat = require("./logcat");
|
|
26
26
|
var _sharedUtils = require("@aiot-toolkit/shared-utils");
|
|
27
27
|
var _ILog = require("@aiot-toolkit/shared-utils/lib/interface/ILog");
|
|
28
|
+
var _grpc = require("./grpc");
|
|
28
29
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
30
|
// TODO: 升级构建工具支持 esm @xujunjie
|
|
30
31
|
const getPort = (async () => {
|
|
@@ -364,7 +365,7 @@ class VvdManager {
|
|
|
364
365
|
const qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
365
366
|
|
|
366
367
|
// qt windows 配置
|
|
367
|
-
const windowOption = options.qtHideWindow ? `-
|
|
368
|
+
const windowOption = options.qtHideWindow ? `-no-window` : '';
|
|
368
369
|
let grpcStr = options.grpcPort ? `-grpc ${options.grpcPort}` : '';
|
|
369
370
|
let serialStr = ``;
|
|
370
371
|
if (options.serialPort) {
|
|
@@ -383,11 +384,14 @@ class VvdManager {
|
|
|
383
384
|
_ColorConsole.default.throw(errMsg);
|
|
384
385
|
throw new Error(errMsg);
|
|
385
386
|
}
|
|
386
|
-
const imageDir = _path.default.resolve(vvdInfo.customImagePath || vvdInfo.imageDir);
|
|
387
387
|
for (const file of this.binFiles) {
|
|
388
388
|
const pOfVvd = _path.default.join(vvdDir, file);
|
|
389
|
-
|
|
390
|
-
if (
|
|
389
|
+
let pOfImageDir;
|
|
390
|
+
if (vvdInfo.customImagePath && _fs.default.existsSync(_path.default.join(vvdInfo.customImagePath, file))) {
|
|
391
|
+
pOfImageDir = _path.default.join(vvdInfo.customImagePath, file);
|
|
392
|
+
} else if (vvdInfo.imageDir && _fs.default.existsSync(_path.default.join(vvdInfo.imageDir, file))) {
|
|
393
|
+
pOfImageDir = _path.default.join(vvdInfo.imageDir, file);
|
|
394
|
+
} else continue;
|
|
391
395
|
if (!_fs.default.existsSync(pOfVvd)) {
|
|
392
396
|
// 文件不存在则直接复制
|
|
393
397
|
_fs.default.copyFileSync(pOfImageDir, pOfVvd);
|
|
@@ -443,7 +447,9 @@ class VvdManager {
|
|
|
443
447
|
});
|
|
444
448
|
return {
|
|
445
449
|
coldBoot: false,
|
|
446
|
-
emulatorInstance
|
|
450
|
+
emulatorInstance,
|
|
451
|
+
getAgent: () => (0, _grpc.createGrpcClient)(e),
|
|
452
|
+
grpcConfig: e
|
|
447
453
|
};
|
|
448
454
|
}
|
|
449
455
|
|
|
@@ -465,10 +471,10 @@ class VvdManager {
|
|
|
465
471
|
}
|
|
466
472
|
|
|
467
473
|
// 利用 readline 接口可解决子进程日志换行的问题
|
|
468
|
-
const readlines = (0, _logcat.attachReadline)(emulatorProcess,
|
|
474
|
+
const readlines = (0, _logcat.attachReadline)(emulatorProcess, onStdout, onErrout);
|
|
475
|
+
const emulatorStartedHandler = msg => {
|
|
469
476
|
if (func(msg)) {
|
|
470
|
-
const
|
|
471
|
-
const e = runningVvds.find(e => e['avd.id'] === vvdName);
|
|
477
|
+
const e = (0, _emulatorutil.getRunningAvdConfigByName)(vvdName);
|
|
472
478
|
if (e) {
|
|
473
479
|
const emulatorInstance = (0, _instance.findInstance)(vvdInfo.imageType, {
|
|
474
480
|
serialPort: e['port.serial'],
|
|
@@ -481,16 +487,19 @@ class VvdManager {
|
|
|
481
487
|
customLogger: options.customLogger
|
|
482
488
|
});
|
|
483
489
|
logger(`${options.vvdName} started successfully`);
|
|
490
|
+
readlines.stdoutReadline.off('line', emulatorStartedHandler);
|
|
484
491
|
resolve({
|
|
485
492
|
coldBoot: true,
|
|
486
|
-
emulatorInstance
|
|
493
|
+
emulatorInstance,
|
|
494
|
+
getAgent: () => (0, _grpc.createGrpcClient)(e),
|
|
495
|
+
grpcConfig: e
|
|
487
496
|
});
|
|
488
497
|
} else {
|
|
489
498
|
reject('get emulator running config failed');
|
|
490
499
|
}
|
|
491
500
|
}
|
|
492
|
-
|
|
493
|
-
|
|
501
|
+
};
|
|
502
|
+
readlines.stdoutReadline.on('line', emulatorStartedHandler);
|
|
494
503
|
|
|
495
504
|
// 监听模拟器的退出事件
|
|
496
505
|
emulatorProcess.on('exit', code => {
|
|
@@ -524,7 +533,11 @@ class VvdManager {
|
|
|
524
533
|
(0, _adb.execAdbCmdAsync)(`adb -s emulator-${config['port.serial']} shell poweroff`).then(() => {
|
|
525
534
|
clearTimeout(t);
|
|
526
535
|
resolve();
|
|
527
|
-
}).catch(
|
|
536
|
+
}).catch(e => {
|
|
537
|
+
if (e?.message?.includes(`device 'emulator-${config['port.serial']}' not found`)) {
|
|
538
|
+
// 清理之前的文件
|
|
539
|
+
_fs.default.unlinkSync(config.path);
|
|
540
|
+
}
|
|
528
541
|
(0, _utils.killProcessByCmd)(config['avd.name']).then(() => {
|
|
529
542
|
clearTimeout(t);
|
|
530
543
|
resolve();
|
package/lib/vvd/logcat.js
CHANGED
|
@@ -51,6 +51,9 @@ function attachReadline(p, onStdout, onErrout) {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
function dispose() {
|
|
54
|
+
p?.removeAllListeners();
|
|
55
|
+
stdoutReadline?.removeAllListeners();
|
|
56
|
+
stderrReadline?.removeAllListeners();
|
|
54
57
|
stdoutReadline?.close();
|
|
55
58
|
stderrReadline?.close();
|
|
56
59
|
stdoutReadline = undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/emulator",
|
|
3
|
-
"version": "2.0.5-beta.
|
|
3
|
+
"version": "2.0.5-beta.21",
|
|
4
4
|
"description": "vela emulator tool.",
|
|
5
5
|
"homepage": "",
|
|
6
6
|
"license": "ISC",
|
|
@@ -36,8 +36,10 @@
|
|
|
36
36
|
"emulator"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@aiot-toolkit/shared-utils": "2.0.5-beta.
|
|
40
|
-
"@
|
|
39
|
+
"@aiot-toolkit/shared-utils": "2.0.5-beta.21",
|
|
40
|
+
"@grpc/grpc-js": "^1.13.3",
|
|
41
|
+
"@grpc/proto-loader": "^0.7.13",
|
|
42
|
+
"@miwt/adb": "0.10.1",
|
|
41
43
|
"adm-zip": "^0.5.16",
|
|
42
44
|
"dayjs": "^1.11.12",
|
|
43
45
|
"find-process": "^1.4.7",
|
|
@@ -51,5 +53,5 @@
|
|
|
51
53
|
"@types/adm-zip": "^0.5.5",
|
|
52
54
|
"@types/ini": "^4.1.1"
|
|
53
55
|
},
|
|
54
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "bd68bd780bf1d12ca6f2bb4179b2759316d958a7"
|
|
55
57
|
}
|