Get files from Flipper folder for every app on an iOS device

Summary:
Design doc: https://docs.google.com/document/d/1HLCFl46RfqG0o1mSt8SWrwf_HMfOCRg_oENioc1rkvQ/edit#

Fetch list of files in the `/sonar` folder on iOS devices and fetch all the files

Reviewed By: passy

Differential Revision: D40548410

fbshipit-source-id: d38cbbb1e3b5579c13f30777233e3caf7b8c9b34
This commit is contained in:
Andrey Goncharov
2022-10-25 05:31:48 -07:00
committed by Facebook GitHub Bot
parent 3c8ebf105a
commit 821bf2b5b7
3 changed files with 228 additions and 5 deletions

View File

@@ -7,15 +7,25 @@
* @format
*/
import {DeviceType, timeout} from 'flipper-common';
import {DeviceDebugData, DeviceType, timeout} from 'flipper-common';
import {ChildProcess} from 'child_process';
import {IOSBridge} from './IOSBridge';
import {ServerDevice} from '../ServerDevice';
import {FlipperServerImpl} from '../../FlipperServerImpl';
import {iOSCrashWatcher} from './iOSCrashUtils';
import {iOSLogListener} from './iOSLogListener';
import {DebuggableDevice} from '../DebuggableDevice';
import tmp, {DirOptions} from 'tmp';
import {promisify} from 'util';
import path from 'path';
import {readFile} from 'fs/promises';
export default class IOSDevice extends ServerDevice {
const tmpDir = promisify(tmp.dir) as (options?: DirOptions) => Promise<string>;
export default class IOSDevice
extends ServerDevice
implements DebuggableDevice
{
private recording?: {process: ChildProcess; destination: string};
private iOSBridge: IOSBridge;
readonly logListener: iOSLogListener;
@@ -128,6 +138,111 @@ export default class IOSDevice extends ServerDevice {
);
}
async readFlipperFolderForAllApps(): Promise<DeviceDebugData[]> {
console.debug('IOSDevice.readFlipperFolderForAllApps', this.info.serial);
const installedApps = await this.iOSBridge.getInstalledApps(
this.info.serial,
);
const userApps = installedApps.filter(
({installType}) =>
installType === 'user' || installType === 'user_development',
);
console.debug(
'IOSDevice.readFlipperFolderForAllApps -> found apps',
this.info.serial,
userApps,
);
const appsCommandsResults = await Promise.all(
userApps.map(async (userApp): Promise<DeviceDebugData | undefined> => {
let sonarDirFileNames: string[];
try {
sonarDirFileNames = await this.iOSBridge.ls(
this.info.serial,
userApp.bundleID,
'/Library/Application Support/sonar',
);
} catch (e) {
console.debug(
'IOSDevice.readFlipperFolderForAllApps -> ignoring app as it does not have sonar dir',
this.info.serial,
userApp.bundleID,
);
return;
}
const dir = await tmpDir({unsafeCleanup: true});
const sonarDirContent = await Promise.all(
sonarDirFileNames.map(async (fileName) => {
const filePath = `/Library/Application Support/sonar/${fileName}`;
if (fileName.endsWith('pem')) {
return {
path: filePath,
data: '===SECURE_CONTENT===',
};
}
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 wranings.',
this.info.serial,
userApp.bundleID,
fileName,
filePath,
);
}
return {
path: filePath,
data: await readFile(path.join(dir, fileName), {
encoding: 'utf-8',
}),
};
}),
);
return {
serial: this.info.serial,
appId: userApp.bundleID,
data: [
{
command: 'iOSBridge.ls /Library/Application Support/sonar',
result: sonarDirFileNames.join('\n'),
},
...sonarDirContent,
],
};
}),
);
return (
appsCommandsResults
// Filter out apps without Flipper integration
.filter((res): res is DeviceDebugData => !!res)
);
}
disconnect() {
if (this.recording) {
this.stopScreenCapture();