From f4b0898de540c95457abe783f03e866c5d846468 Mon Sep 17 00:00:00 2001 From: Shaheen Gandhi Date: Wed, 15 Apr 2020 11:22:42 -0700 Subject: [PATCH] Refactor command execution fallback for both push and pull Summary: D20920582 was unfortunately not enough to fix ability for Flipper to connect to packages that are running as services without an `` tag in the manifest. The issue there is that the push of `sonarCA.crt` succeeded due to erroneous changes to the target package. This change ensures both pull and push are covered. Reviewed By: jknoxville Differential Revision: D21024673 fbshipit-source-id: cad86ba9ae3b02a99187d3f6bd3b500d2a4b971a --- .../utils/androidContainerUtilityInternal.tsx | 81 +++++++++++++------ 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/desktop/app/src/utils/androidContainerUtilityInternal.tsx b/desktop/app/src/utils/androidContainerUtilityInternal.tsx index 6f6a1d80f..4e364aac8 100644 --- a/desktop/app/src/utils/androidContainerUtilityInternal.tsx +++ b/desktop/app/src/utils/androidContainerUtilityInternal.tsx @@ -72,12 +72,24 @@ export function _push( contents: FileContent, ): Promise { console.debug(`Deploying ${filename} to ${deviceId}:${app}`, logTag); - return executeCommandAsApp( - client, - deviceId, - app, - `echo "${contents}" > '${filename}' && chmod 644 '${filename}'`, - ).then((_) => undefined); + const command = `echo "${contents}" > '${filename}' && chmod 644 '${filename}'`; + return executeCommandAsApp(client, deviceId, app, command) + .then((_) => undefined) + .catch((error) => { + if ( + error instanceof RunAsError && + error.code == RunAsErrorCode.NotAnApp + ) { + // Fall back to running the command directly. This will work if adb is running as root. + return executeCommandWithSu(client, deviceId, app, command) + .then((_) => undefined) + .catch((e) => { + console.debug(e); + throw error; + }); + } + throw error; + }); } export function _pull( @@ -86,24 +98,18 @@ export function _pull( app: AppName, path: FilePath, ): Promise { - return executeCommandAsApp(client, deviceId, app, `cat '${path}'`).catch( - (error) => { - if ( - error instanceof RunAsError && - error.code == RunAsErrorCode.NotAnApp - ) { - // Fall back to running the command directly. This will work if adb is running as root. - return client - .shell(deviceId, `echo "cat ${path}" | su`) - .then(adbkit.util.readAll) - .then((buffer) => buffer.toString()) - .catch(() => { - throw error; - }); - } - throw error; - }, - ); + const command = `cat '${path}'`; + return executeCommandAsApp(client, deviceId, app, command).catch((error) => { + if (error instanceof RunAsError && error.code == RunAsErrorCode.NotAnApp) { + // Fall back to running the command directly. This will work if adb is running as root. + return executeCommandWithSu(client, deviceId, app, command).catch((e) => { + // Throw the original error. + console.debug(e); + throw error; + }); + } + throw error; + }); } // Keep this method private since it relies on pre-validated arguments @@ -112,9 +118,34 @@ function executeCommandAsApp( deviceId: string, app: string, command: string, +): Promise { + return _executeCommandWithRunner( + client, + deviceId, + app, + command, + `run-as '${app}'`, + ); +} + +function executeCommandWithSu( + client: Client, + deviceId: string, + app: string, + command: string, +): Promise { + return _executeCommandWithRunner(client, deviceId, app, command, 'su'); +} + +function _executeCommandWithRunner( + client: Client, + deviceId: string, + app: string, + command: string, + runner: string, ): Promise { return client - .shell(deviceId, `echo '${command}' | run-as '${app}'`) + .shell(deviceId, `echo '${command}' | ${runner}`) .then(adbkit.util.readAll) .then((buffer) => buffer.toString()) .then((output) => {