nativescript
Version:
Command-line interface for building NativeScript projects
181 lines • 8.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AndroidEmulatorServices = void 0;
const constants_1 = require("../../constants");
const helpers_1 = require("../../helpers");
const os_1 = require("os");
const _ = require("lodash");
const constants_2 = require("../../../constants");
const yok_1 = require("../../yok");
const semver = require("semver");
class AndroidEmulatorServices {
constructor($androidGenymotionService, $androidVirtualDeviceService, $adb, $childProcess, $emulatorHelper, $logger, $utils) {
this.$androidGenymotionService = $androidGenymotionService;
this.$androidVirtualDeviceService = $androidVirtualDeviceService;
this.$adb = $adb;
this.$childProcess = $childProcess;
this.$emulatorHelper = $emulatorHelper;
this.$logger = $logger;
this.$utils = $utils;
}
async getEmulatorImages() {
const adbDevicesOutput = await this.$adb.getDevicesSafe();
const avdAvailableEmulatorsOutput = await this.$androidVirtualDeviceService.getEmulatorImages(adbDevicesOutput);
const genyAvailableDevicesOutput = await this.$androidGenymotionService.getEmulatorImages(adbDevicesOutput);
const devices = _.concat(avdAvailableEmulatorsOutput.devices, genyAvailableDevicesOutput.devices).filter((item) => !!item);
return {
devices,
errors: avdAvailableEmulatorsOutput.errors.concat(genyAvailableDevicesOutput.errors),
};
}
async getRunningEmulatorIds() {
const adbDevicesOutput = await this.$adb.getDevicesSafe();
const avds = await this.$androidVirtualDeviceService.getRunningEmulatorIds(adbDevicesOutput);
const genies = await this.$androidGenymotionService.getRunningEmulatorIds(adbDevicesOutput);
return avds.concat(genies);
}
async getRunningEmulatorName(emulatorId) {
let result = await this.$androidVirtualDeviceService.getRunningEmulatorName(emulatorId);
if (!result) {
result = await this.$androidGenymotionService.getRunningEmulatorName(emulatorId);
}
return result;
}
async getRunningEmulatorImageIdentifier(emulatorId) {
let result = await this.$androidVirtualDeviceService.getRunningEmulatorImageIdentifier(emulatorId);
if (!result) {
result = await this.$androidGenymotionService.getRunningEmulatorImageIdentifier(emulatorId);
}
return result;
}
async startEmulator(options) {
const output = await this.startEmulatorCore(options);
let bootToCompleteOutput = null;
if (output && output.runningEmulator) {
bootToCompleteOutput = await this.waitForEmulatorBootToComplete(output.runningEmulator, output.endTimeEpoch, options.timeout);
}
return {
errors: ((output && output.errors) || []).concat((bootToCompleteOutput && bootToCompleteOutput.errors) || []),
};
}
detach(deviceInfo) {
this.$androidVirtualDeviceService.detach(deviceInfo);
}
async startEmulatorCore(options) {
const timeout = options.timeout || constants_1.AndroidVirtualDevice.TIMEOUT_SECONDS;
const endTimeEpoch = (0, helpers_1.getCurrentEpochTime)() + this.$utils.getMilliSecondsTimeout(timeout);
const availableEmulators = (await this.getEmulatorImages()).devices;
let emulator = this.$emulatorHelper.getEmulatorByStartEmulatorOptions(options, availableEmulators);
if (!emulator &&
!options.emulatorIdOrName &&
!options.imageIdentifier &&
!options.emulator) {
emulator = this.getBestFit(availableEmulators);
}
if (!emulator) {
return {
runningEmulator: null,
errors: [
`No emulator image available for device identifier '${options.emulatorIdOrName || options.imageIdentifier}'.`,
],
endTimeEpoch,
};
}
if (emulator.errorHelp) {
return {
runningEmulator: null,
errors: [emulator.errorHelp],
endTimeEpoch,
};
}
this.spawnEmulator(emulator);
const isInfiniteWait = this.$utils.getMilliSecondsTimeout(timeout) === 0;
let hasTimeLeft = (0, helpers_1.getCurrentEpochTime)() < endTimeEpoch;
while (hasTimeLeft || isInfiniteWait) {
const emulators = (await this.getEmulatorImages()).devices;
const newEmulator = _.find(emulators, (e) => e.imageIdentifier === emulator.imageIdentifier);
if (newEmulator && this.$emulatorHelper.isEmulatorRunning(newEmulator)) {
return {
runningEmulator: newEmulator,
errors: [],
endTimeEpoch,
};
}
await (0, helpers_1.sleep)(10000); // the emulator definitely takes its time to wake up
hasTimeLeft = (0, helpers_1.getCurrentEpochTime)() < endTimeEpoch;
}
if (!hasTimeLeft && !isInfiniteWait) {
return {
runningEmulator: null,
errors: [constants_1.AndroidVirtualDevice.UNABLE_TO_START_EMULATOR_MESSAGE],
endTimeEpoch,
};
}
}
spawnEmulator(emulator) {
let pathToEmulatorExecutable = null;
let startEmulatorArgs = null;
if (emulator.vendor === constants_1.AndroidVirtualDevice.AVD_VENDOR_NAME) {
pathToEmulatorExecutable = this.$androidVirtualDeviceService
.pathToEmulatorExecutable;
startEmulatorArgs = this.$androidVirtualDeviceService.startEmulatorArgs(emulator.imageIdentifier);
}
else if (emulator.vendor === constants_1.AndroidVirtualDevice.GENYMOTION_VENDOR_NAME) {
pathToEmulatorExecutable = this.$androidGenymotionService
.pathToEmulatorExecutable;
startEmulatorArgs = this.$androidGenymotionService.startEmulatorArgs(emulator.imageIdentifier);
}
this.$logger.info(`Starting Android emulator with image ${emulator.imageIdentifier}`);
const childProcess = this.$childProcess.spawn(pathToEmulatorExecutable, startEmulatorArgs, { stdio: "ignore", detached: true });
childProcess.unref();
childProcess.on("error", (err) => {
this.$logger.trace(`Error when starting emulator. More info: ${err}`);
});
}
getBestFit(emulators) {
let best = null;
for (const emulator of emulators) {
const currentVersion = emulator.version && semver.coerce(emulator.version);
const currentBestVersion = best && best.version && semver.coerce(best.version);
if (!best ||
(currentVersion &&
currentBestVersion &&
semver.gt(currentVersion, currentBestVersion))) {
best = emulator;
}
}
const minVersion = semver.coerce(constants_1.AndroidVirtualDevice.MIN_ANDROID_VERSION);
const bestVersion = best && best.version && semver.coerce(best.version);
return bestVersion && semver.gte(bestVersion, minVersion) ? best : null;
}
async waitForEmulatorBootToComplete(emulator, endTimeEpoch, timeout) {
this.$logger.info("Waiting for emulator device initialization...", {
[constants_2.LoggerConfigData.skipNewLine]: true,
});
const isInfiniteWait = this.$utils.getMilliSecondsTimeout(timeout || constants_1.AndroidVirtualDevice.TIMEOUT_SECONDS) === 0;
while ((0, helpers_1.getCurrentEpochTime)() < endTimeEpoch || isInfiniteWait) {
const isEmulatorBootCompleted = await this.isEmulatorBootCompleted(emulator.identifier);
if (isEmulatorBootCompleted) {
this.$logger.info(os_1.EOL, { [constants_2.LoggerConfigData.skipNewLine]: true });
return {
runningEmulator: emulator,
errors: [],
};
}
this.$logger.info(".", { [constants_2.LoggerConfigData.skipNewLine]: true });
await (0, helpers_1.sleep)(10000);
}
return {
runningEmulator: null,
errors: [constants_1.AndroidVirtualDevice.UNABLE_TO_START_EMULATOR_MESSAGE],
};
}
async isEmulatorBootCompleted(emulatorId) {
const output = await this.$adb.getPropertyValue(emulatorId, "dev.bootcomplete");
const matches = output.match("1");
return matches && matches.length > 0;
}
}
exports.AndroidEmulatorServices = AndroidEmulatorServices;
yok_1.injector.register("androidEmulatorServices", AndroidEmulatorServices);
//# sourceMappingURL=android-emulator-services.js.map