From 99bb43fe323946e3080b9ccfe226a89ed5977082 Mon Sep 17 00:00:00 2001 From: John Knox Date: Wed, 27 Feb 2019 05:39:04 -0800 Subject: [PATCH] Move adb client creation into it's own file Summary: Allows the created client to be reused. Reviewed By: passy Differential Revision: D14241449 fbshipit-source-id: 6bbb64eeb708dce9c24e4581e8480d19af998e47 --- src/dispatcher/androidDevice.js | 59 +-------------------------- src/utils/adbClient.js | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 src/utils/adbClient.js diff --git a/src/dispatcher/androidDevice.js b/src/dispatcher/androidDevice.js index 9cb3b5f3e..ce89a9573 100644 --- a/src/dispatcher/androidDevice.js +++ b/src/dispatcher/androidDevice.js @@ -7,15 +7,11 @@ import AndroidDevice from '../devices/AndroidDevice'; import child_process from 'child_process'; -import promiseRetry from 'promise-retry'; -import {promisify} from 'util'; import type {Store} from '../reducers/index.js'; import type BaseDevice from '../devices/BaseDevice'; import type {Logger} from '../fb-interfaces/Logger.js'; import {registerDeviceCallbackOnPlugins} from '../utils/onRegisterDevice.js'; -import {reportPlatformFailures} from '../utils/metrics'; -import adbConfig from '../utils/adbConfig'; -const adb = require('adbkit-fb'); +import {getAdbClient} from '../utils/adbClient'; function createDevice( adbClient: any, @@ -64,57 +60,6 @@ function getRunningEmulatorName(id: string): Promise { } export default (store: Store, logger: Logger) => { - /* Adbkit will attempt to start the adb server if it's not already running, - however, it sometimes fails with ENOENT errors. So instead, we start it - manually before requesting a client. */ - function createClient() { - const adbPath = process.env.ANDROID_HOME - ? `${process.env.ANDROID_HOME}/platform-tools/adb` - : 'adb'; - return reportPlatformFailures( - promisify(child_process.exec)(`${adbPath} start-server`) - .then(result => { - if (result.error) { - throw new Error( - `Failed to start adb server: ${result.stderr.toString()}`, - ); - } - }) - .then(() => adb.createClient(adbConfig())), - 'createADBClient.shell', - ).catch(err => { - console.error( - 'Failed to create adb client using shell adb command. Trying with adbkit', - ); - - /* In the event that starting adb with the above method fails, fallback - to using adbkit, though its known to be unreliable. */ - const unsafeClient = adb.createClient(adbConfig()); - return reportPlatformFailures( - promiseRetry( - (retry, number) => { - return unsafeClient - .listDevices() - .then(() => { - return unsafeClient; - }) - .catch(e => { - console.warn( - `Failed to start adb client. Retrying. ${e.message}`, - ); - retry(e); - }); - }, - { - minTimeout: 200, - retries: 5, - }, - ), - 'createADBClient.adbkit', - ); - }); - } - const watchAndroidDevices = () => { // get emulators child_process.exec( @@ -132,7 +77,7 @@ export default (store: Store, logger: Logger) => { }, ); - reportPlatformFailures(createClient(), 'createADBClient') + getAdbClient() .then(client => { client .trackDevices() diff --git a/src/utils/adbClient.js b/src/utils/adbClient.js new file mode 100644 index 000000000..a993121e5 --- /dev/null +++ b/src/utils/adbClient.js @@ -0,0 +1,72 @@ +/** + * Copyright 2018-present Facebook. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * @format + */ +import {reportPlatformFailures} from './metrics'; +import {promisify} from 'util'; +import child_process from 'child_process'; +import promiseRetry from 'promise-retry'; +import adbConfig from '../utils/adbConfig'; +import adbkit from 'adbkit-fb'; + +let instance; + +export function getAdbClient(): Promise { + if (!instance) { + instance = reportPlatformFailures(createClient(), 'createADBClient'); + } + return instance; +} + +/* Adbkit will attempt to start the adb server if it's not already running, + however, it sometimes fails with ENOENT errors. So instead, we start it + manually before requesting a client. */ +function createClient() { + const adbPath = process.env.ANDROID_HOME + ? `${process.env.ANDROID_HOME}/platform-tools/adb` + : 'adb'; + return reportPlatformFailures( + promisify(child_process.exec)(`${adbPath} start-server`) + .then(result => { + if (result.error) { + throw new Error( + `Failed to start adb server: ${result.stderr.toString()}`, + ); + } + }) + .then(() => adbkit.createClient(adbConfig())), + 'createADBClient.shell', + ).catch(err => { + console.error( + 'Failed to create adb client using shell adb command. Trying with adbkit', + ); + + /* In the event that starting adb with the above method fails, fallback + to using adbkit, though its known to be unreliable. */ + const unsafeClient = adbkit.createClient(adbConfig()); + return reportPlatformFailures( + promiseRetry( + (retry, number) => { + return unsafeClient + .listDevices() + .then(() => { + return unsafeClient; + }) + .catch(e => { + console.warn( + `Failed to start adb client. Retrying. ${e.message}`, + ); + retry(e); + }); + }, + { + minTimeout: 200, + retries: 5, + }, + ), + 'createADBClient.adbkit', + ); + }); +}