From e886427003f57497d607e59d1743d9023f58c874 Mon Sep 17 00:00:00 2001 From: Andrey Goncharov Date: Tue, 25 Oct 2022 05:31:48 -0700 Subject: [PATCH] Make device debug info fetching fault tolerant Summary: Design doc: https://docs.google.com/document/d/1HLCFl46RfqG0o1mSt8SWrwf_HMfOCRg_oENioc1rkvQ/edit# Some files on the devices could be unavailable due to lack of permissions (hello SELinux and enterprise builds of iOS apps). Instead of failing the export, we should fetch what we can. Reviewed By: passy Differential Revision: D40551931 fbshipit-source-id: 698e157b1283b9e959909b6439cd09d2dc8dc8d6 --- .../src/FlipperServerImpl.tsx | 16 +++- .../src/devices/android/AndroidDevice.tsx | 44 +++++++---- .../src/devices/ios/IOSDevice.tsx | 74 ++++++++++--------- 3 files changed, 84 insertions(+), 50 deletions(-) diff --git a/desktop/flipper-server-core/src/FlipperServerImpl.tsx b/desktop/flipper-server-core/src/FlipperServerImpl.tsx index 9679c26b5..33297f006 100644 --- a/desktop/flipper-server-core/src/FlipperServerImpl.tsx +++ b/desktop/flipper-server-core/src/FlipperServerImpl.tsx @@ -25,6 +25,7 @@ import { FlipperServerConfig, Logger, FlipperServerExecOptions, + DeviceDebugData, } from 'flipper-common'; import {ServerDevice} from './devices/ServerDevice'; import {Base64} from 'js-base64'; @@ -611,10 +612,21 @@ export class FlipperServerImpl implements FlipperServer { (device.info.os === 'Android' || device.info.os === 'iOS'), ) .map((device) => - (device as unknown as DebuggableDevice).readFlipperFolderForAllApps(), + (device as unknown as DebuggableDevice) + .readFlipperFolderForAllApps() + + .catch((e) => { + console.warn( + 'fetchDebugLogs -> could not fetch debug data', + device.info.serial, + e, + ); + }), ), ); - return debugDataForEachDevice.flat(); + return debugDataForEachDevice + .filter((item): item is DeviceDebugData[] => !!item) + .flat(); } public async close() { diff --git a/desktop/flipper-server-core/src/devices/android/AndroidDevice.tsx b/desktop/flipper-server-core/src/devices/android/AndroidDevice.tsx index ba8a681cd..ba5154a20 100644 --- a/desktop/flipper-server-core/src/devices/android/AndroidDevice.tsx +++ b/desktop/flipper-server-core/src/devices/android/AndroidDevice.tsx @@ -315,24 +315,33 @@ export default class AndroidDevice this.info.serial, appId, `find /data/data/${appId}/files/sonar -type f -printf "%f\n"`, - ).then((output) => { - if (output.includes('No such file or directory')) { + ) + .then((output) => { + if (output.includes('No such file or directory')) { + console.debug( + 'AndroidDevice.readFlipperFolderForAllApps -> skipping app because sonar dir does not exist', + this.info.serial, + appId, + ); + return; + } + + return ( + output + .split('\n') + // Each entry has \n at the end. The last one also has it. + // As a result, there is an "" (empty string) item at the end after the split. + .filter((appId) => appId !== '') + ); + }) + .catch((e) => { console.debug( - 'AndroidDevice.readFlipperFolderForAllApps -> skipping app because sonar dir does not exist', + 'AndroidDevice.readFlipperFolderForAllApps -> failed to fetch sonar dir', this.info.serial, appId, + e, ); - return; - } - - return ( - output - .split('\n') - // Each entry has \n at the end. The last one also has it. - // As a result, there is an "" (empty string) item at the end after the split. - .filter((appId) => appId !== '') - ); - }); + }); if (!sonarDirFileNames) { return; @@ -349,7 +358,12 @@ export default class AndroidDevice } return { path: filePath, - data: await pull(this.adb, this.info.serial, appId, filePath), + data: await pull( + this.adb, + this.info.serial, + appId, + filePath, + ).catch((e) => `Couldn't pull the file: ${e}`), }; }, ); diff --git a/desktop/flipper-server-core/src/devices/ios/IOSDevice.tsx b/desktop/flipper-server-core/src/devices/ios/IOSDevice.tsx index b184114c5..d5ab8fad7 100644 --- a/desktop/flipper-server-core/src/devices/ios/IOSDevice.tsx +++ b/desktop/flipper-server-core/src/devices/ios/IOSDevice.tsx @@ -184,41 +184,49 @@ export default class IOSDevice }; } try { - await this.iOSBridge.pull( - this.info.serial, - filePath, - userApp.bundleID, - dir, - ); + // See iOSCertificateProvider to learn why we need 2 pulls + try { + await this.iOSBridge.pull( + this.info.serial, + filePath, + userApp.bundleID, + dir, + ); + } catch (e) { + console.debug( + 'IOSDevice.readFlipperFolderForAllApps -> Original idb pull failed. Most likely it is a physical device that requires us to handle the dest path dirrently. Forcing a re-try with the updated dest path. See D32106952 for details. Original error:', + this.info.serial, + userApp.bundleID, + fileName, + filePath, + e, + ); + await this.iOSBridge.pull( + this.info.serial, + filePath, + userApp.bundleID, + path.join(dir, fileName), + ); + console.debug( + 'IOSDevice.readFlipperFolderForAllApps -> Subsequent idb pull succeeded. Nevermind previous warnings.', + this.info.serial, + userApp.bundleID, + fileName, + filePath, + ); + } + return { + path: filePath, + data: await readFile(path.join(dir, fileName), { + encoding: 'utf-8', + }), + }; } catch (e) { - console.debug( - 'IOSDevice.readFlipperFolderForAllApps -> Original idb pull failed. Most likely it is a physical device that requires us to handle the dest path dirrently. Forcing a re-try with the updated dest path. See D32106952 for details. Original error:', - this.info.serial, - userApp.bundleID, - fileName, - filePath, - e, - ); - await this.iOSBridge.pull( - this.info.serial, - filePath, - userApp.bundleID, - path.join(dir, fileName), - ); - console.debug( - 'IOSDevice.readFlipperFolderForAllApps -> Subsequent idb pull succeeded. Nevermind previous wranings.', - this.info.serial, - userApp.bundleID, - fileName, - filePath, - ); + return { + path: filePath, + data: `Couldn't pull the file: ${e}`, + }; } - return { - path: filePath, - data: await readFile(path.join(dir, fileName), { - encoding: 'utf-8', - }), - }; }), );