support user defined device plugins

Summary:
* move CPU and Logs plugin to plugins directory, set up package.json for them
* adjust plugins/index.js to expose device and client plugins in the same place, adding two new exports

Reviewed By: danielbuechele

Differential Revision: D10247606

fbshipit-source-id: 347bf8b3f9629987ad29d1d2ed025e0c88b9c967
This commit is contained in:
Alex Langenfeld
2018-10-10 18:28:23 -07:00
committed by Facebook Github Bot
parent 7527636a38
commit f3d2e0983e
15 changed files with 129 additions and 48 deletions

369
src/plugins/cpu/index.js Normal file
View File

@@ -0,0 +1,369 @@
/**
* 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 {FlipperDevicePlugin, Device} from 'flipper';
var adb = require('adbkit-fb');
import {
FlexColumn,
FlexRow,
Button,
Toolbar,
Text,
ManagedTable,
colors,
} from 'flipper';
type ADBClient = any;
type AndroidDevice = {
adb: ADBClient,
};
type TableRows = any;
// we keep vairable name with underline for to physical path mappings on device
type CPUFrequency = {|
cpu_id: number,
scaling_cur_freq: number,
scaling_min_freq: number,
scaling_max_freq: number,
cpuinfo_max_freq: number,
cpuinfo_min_freq: number,
|};
type CPUState = {|
cpuFreq: Array<CPUFrequency>,
cpuCount: number,
monitoring: boolean,
hardwareInfo: string,
|};
type ShellCallBack = (output: string) => void;
const ColumnSizes = {
cpu_id: '10%',
scaling_cur_freq: 'flex',
scaling_min_freq: 'flex',
scaling_max_freq: 'flex',
cpuinfo_min_freq: 'flex',
cpuinfo_max_freq: 'flex',
};
const Columns = {
cpu_id: {
value: 'CPU ID',
resizable: true,
},
scaling_cur_freq: {
value: 'Scaling Current',
resizable: true,
},
scaling_min_freq: {
value: 'Scaling MIN',
resizable: true,
},
scaling_max_freq: {
value: 'Scaling MAX',
resizable: true,
},
cpuinfo_min_freq: {
value: 'MIN Frequency',
resizable: true,
},
cpuinfo_max_freq: {
value: 'MAX Frequency',
resizable: true,
},
};
// check if str is a number
function isNormalInteger(str) {
let n = Math.floor(Number(str));
return String(n) === str && n >= 0;
}
// format frequency to MHz, GHz
function formatFrequency(freq) {
if (freq == -1) {
return 'N/A';
} else if (freq == -2) {
return 'off';
} else if (freq > 1000 * 1000) {
return (freq / 1000 / 1000).toFixed(2) + ' GHz';
} else {
return freq / 1000 + ' MHz';
}
}
export default class CPUFrequencyTable extends FlipperDevicePlugin<CPUState> {
static id = 'DeviceCPU';
static title = 'CPU';
static icon = 'underline';
adbClient: ADBClient;
intervalID: ?IntervalID;
state = {
cpuFreq: [],
cpuCount: 0,
monitoring: false,
hardwareInfo: '',
};
static supportsDevice(device: Device) {
return device.os === 'Android' && device.deviceType === 'physical';
}
init() {
let device = ((this.device: any): AndroidDevice);
this.adbClient = device.adb;
this.updateHardwareInfo();
// check how many cores we have on this device
this.executeShell((output: string) => {
let idx = output.indexOf('-');
let cpuFreq = [];
let count = parseInt(output.substring(idx + 1), 10) + 1;
for (let i = 0; i < count; ++i) {
cpuFreq[i] = {
cpu_id: i,
scaling_cur_freq: -1,
scaling_min_freq: -1,
scaling_max_freq: -1,
cpuinfo_min_freq: -1,
cpuinfo_max_freq: -1,
};
}
this.setState({
cpuCount: count,
cpuFreq: cpuFreq,
});
}, 'cat /sys/devices/system/cpu/possible');
}
executeShell = (callback: ShellCallBack, command: string) => {
this.adbClient
.shell(this.device.serial, command)
.then(adb.util.readAll)
.then(function(output) {
return callback(output.toString().trim());
});
};
updateCoreFrequency = (core: number, type: string) => {
this.executeShell((output: string) => {
let cpuFreq = this.state.cpuFreq;
let newFreq = isNormalInteger(output) ? parseInt(output, 10) : -1;
// update table only if frequency changed
if (cpuFreq[core][type] != newFreq) {
cpuFreq[core][type] = newFreq;
if (type == 'scaling_cur_freq' && cpuFreq[core][type] < 0) {
// cannot find current freq means offline
cpuFreq[core][type] = -2;
}
this.setState({
cpuFreq: cpuFreq,
});
}
}, 'cat /sys/devices/system/cpu/cpu' + core + '/cpufreq/' + type);
};
readCoreFrequency = (core: number) => {
let freq = this.state.cpuFreq[core];
if (freq.cpuinfo_max_freq < 0) {
this.updateCoreFrequency(core, 'cpuinfo_max_freq');
}
if (freq.cpuinfo_min_freq < 0) {
this.updateCoreFrequency(core, 'cpuinfo_min_freq');
}
this.updateCoreFrequency(core, 'scaling_cur_freq');
this.updateCoreFrequency(core, 'scaling_min_freq');
this.updateCoreFrequency(core, 'scaling_max_freq');
};
updateHardwareInfo = () => {
this.executeShell((output: string) => {
let hwInfo = '';
if (
output.startsWith('msm') ||
output.startsWith('apq') ||
output.startsWith('sdm')
) {
hwInfo = 'QUALCOMM ' + output.toUpperCase();
} else if (output.startsWith('exynos')) {
this.executeShell((output: string) => {
if (output != null) {
this.setState({
hardwareInfo: 'SAMSUMG ' + output.toUpperCase(),
});
}
}, 'getprop ro.chipname');
return;
} else if (output.startsWith('mt')) {
hwInfo = 'MEDIATEK ' + output.toUpperCase();
} else if (output.startsWith('sc')) {
hwInfo = 'SPREADTRUM ' + output.toUpperCase();
} else if (output.startsWith('hi') || output.startsWith('kirin')) {
hwInfo = 'HISILICON ' + output.toUpperCase();
} else if (output.startsWith('rk')) {
hwInfo = 'ROCKCHIP ' + output.toUpperCase();
} else if (output.startsWith('bcm')) {
hwInfo = 'BROADCOM ' + output.toUpperCase();
}
this.setState({
hardwareInfo: hwInfo,
});
}, 'getprop ro.board.platform');
};
onStartMonitor = () => {
if (this.intervalID) {
return;
}
this.intervalID = setInterval(() => {
for (let i = 0; i < this.state.cpuCount; ++i) {
this.readCoreFrequency(i);
}
}, 500);
this.setState({
monitoring: true,
});
};
onStopMonitor = () => {
if (!this.intervalID) {
return;
} else {
clearInterval(this.intervalID);
this.intervalID = null;
this.setState({
monitoring: false,
});
this.cleanup();
}
};
cleanup = () => {
let cpuFreq = this.state.cpuFreq;
for (let i = 0; i < this.state.cpuCount; ++i) {
cpuFreq[i].scaling_cur_freq = -1;
cpuFreq[i].scaling_min_freq = -1;
cpuFreq[i].scaling_max_freq = -1;
// we don't cleanup cpuinfo_min_freq, cpuinfo_max_freq
// because usually they are fixed (hardware)
}
this.setState({
cpuFreq: cpuFreq,
});
};
teardown = () => {
this.cleanup();
};
buildRow = (freq: CPUFrequency) => {
let style = {};
if (freq.scaling_cur_freq == -2) {
style = {
style: {
backgroundColor: colors.blueTint30,
color: colors.white,
fontWeight: 700,
},
};
} else if (
freq.scaling_min_freq != freq.cpuinfo_min_freq &&
freq.scaling_min_freq > 0 &&
freq.cpuinfo_min_freq > 0
) {
style = {
style: {
backgroundColor: colors.redTint,
color: colors.red,
fontWeight: 700,
},
};
} else if (
freq.scaling_max_freq != freq.cpuinfo_max_freq &&
freq.scaling_max_freq > 0 &&
freq.cpuinfo_max_freq > 0
) {
style = {
style: {
backgroundColor: colors.yellowTint,
color: colors.yellow,
fontWeight: 700,
},
};
}
return {
columns: {
cpu_id: {value: <Text>CPU_{freq.cpu_id}</Text>},
scaling_cur_freq: {
value: <Text>{formatFrequency(freq.scaling_cur_freq)}</Text>,
},
scaling_min_freq: {
value: <Text>{formatFrequency(freq.scaling_min_freq)}</Text>,
},
scaling_max_freq: {
value: <Text>{formatFrequency(freq.scaling_max_freq)}</Text>,
},
cpuinfo_min_freq: {
value: <Text>{formatFrequency(freq.cpuinfo_min_freq)}</Text>,
},
cpuinfo_max_freq: {
value: <Text>{formatFrequency(freq.cpuinfo_max_freq)}</Text>,
},
},
key: freq.cpu_id,
style,
};
};
frequencyRows = (cpuFreqs: Array<CPUFrequency>): TableRows => {
let rows = [];
for (const cpuFreq of cpuFreqs) {
rows.push(this.buildRow(cpuFreq));
}
return rows;
};
render() {
return (
<FlexRow>
<FlexColumn fill={true}>
<Toolbar position="top">
{this.state.monitoring ? (
<Button onClick={this.onStopMonitor} icon="pause">
Pause
</Button>
) : (
<Button onClick={this.onStartMonitor} icon="play">
Start
</Button>
)}
&nbsp; {this.state.hardwareInfo}
</Toolbar>
<ManagedTable
multiline={true}
columnSizes={ColumnSizes}
columns={Columns}
autoHeight={true}
floating={false}
zebra={true}
rows={this.frequencyRows(this.state.cpuFreq)}
/>
</FlexColumn>
</FlexRow>
);
}
}

View File

@@ -0,0 +1,9 @@
{
"name": "flipper-plugin-device-cpu",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"adbkit-fb": "2.10.1"
}
}

72
src/plugins/cpu/yarn.lock Normal file
View File

@@ -0,0 +1,72 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
adbkit-fb@2.10.1:
version "2.10.1"
resolved "https://registry.yarnpkg.com/adbkit-fb/-/adbkit-fb-2.10.1.tgz#accd6209d8da9388124ace97f4fc3047aead18cc"
integrity sha512-ERq2JXpDkr/tpSDYKwQ4SbBakozBWnWbz3Pjc8EQ1bGCzxD0XkAnUjTaW4ANX9ijrj/fWgrCqp3FDTNq8fIYDQ==
dependencies:
adbkit-logcat-fb "^1.1.0"
adbkit-monkey "~1.0.1"
bluebird "~2.9.24"
commander "^2.3.0"
debug "~2.6.3"
node-forge "^0.7.1"
split "~0.3.3"
adbkit-logcat-fb@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/adbkit-logcat-fb/-/adbkit-logcat-fb-1.1.0.tgz#af6416c7be95c18220a128a320276602881ec6b7"
integrity sha512-4A4gpQk0Y+xryVvQRkXFTMiqRauwGDQU5CKujymtcS/CQP78oDWfHkbjtm2ryc7O9DqrMlnsGRch1q41ErXJlA==
adbkit-monkey@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/adbkit-monkey/-/adbkit-monkey-1.0.1.tgz#f291be701a2efc567a63fc7aa6afcded31430be1"
integrity sha1-8pG+cBou/FZ6Y/x6pq/N7TFDC+E=
dependencies:
async "~0.2.9"
async@~0.2.9:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
bluebird@~2.9.24:
version "2.9.34"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.9.34.tgz#2f7b4ec80216328a9fddebdf69c8d4942feff7d8"
integrity sha1-L3tOyAIWMoqf3evfacjUlC/v99g=
commander@^2.3.0:
version "2.18.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970"
integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==
debug@~2.6.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
node-forge@^0.7.1:
version "0.7.6"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac"
integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==
split@~0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=
dependencies:
through "2"
through@2:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=