diff --git a/src/dispatcher/androidDevice.js b/src/dispatcher/androidDevice.js index da4b8bd4b..bb7080f51 100644 --- a/src/dispatcher/androidDevice.js +++ b/src/dispatcher/androidDevice.js @@ -11,6 +11,7 @@ import promiseRetry from 'promise-retry'; import type {Store} from '../reducers/index.js'; import type BaseDevice from '../devices/BaseDevice'; import type Logger from '../fb-stubs/Logger.js'; +import {registerDeviceCallbackOnPlugins} from '../utils/onRegisterDevice.js'; const adb = require('adbkit-fb'); function createDevice(adbClient, device): Promise { @@ -165,6 +166,13 @@ export default (store: Store, logger: Logger) => { type: 'REGISTER_DEVICE', payload: androidDevice, }); + + registerDeviceCallbackOnPlugins( + store, + store.getState().plugins.devicePlugins, + store.getState().plugins.clientPlugins, + androidDevice, + ); } async function unregisterDevices(deviceIds: Array) { diff --git a/src/dispatcher/iOSDevice.js b/src/dispatcher/iOSDevice.js index ba2517557..0bb89cb22 100644 --- a/src/dispatcher/iOSDevice.js +++ b/src/dispatcher/iOSDevice.js @@ -18,7 +18,7 @@ import IOSDevice from '../devices/IOSDevice'; import iosUtil from '../fb-stubs/iOSContainerUtility'; import isProduction from '../utils/isProduction.js'; import GK from '../fb-stubs/GK'; - +import {registerDeviceCallbackOnPlugins} from '../utils/onRegisterDevice.js'; type iOSSimulatorDevice = {| state: 'Booted' | 'Shutdown' | 'Shutting Down', availability?: string, @@ -70,10 +70,17 @@ function queryDevices(store: Store, logger: Logger): Promise { name: name, serial: udid, }); + const iOSDevice = new IOSDevice(udid, type, name); store.dispatch({ type: 'REGISTER_DEVICE', - payload: new IOSDevice(udid, type, name), + payload: iOSDevice, }); + registerDeviceCallbackOnPlugins( + store, + store.getState().plugins.devicePlugins, + store.getState().plugins.clientPlugins, + iOSDevice, + ); } } diff --git a/src/dispatcher/plugins.js b/src/dispatcher/plugins.js index e0df904bb..d4beb2a85 100644 --- a/src/dispatcher/plugins.js +++ b/src/dispatcher/plugins.js @@ -56,26 +56,6 @@ export default (store: Store, logger: Logger) => { store.dispatch(addFailedPlugins(failedPlugins)); store.dispatch(registerPlugins(initialPlugins)); - initialPlugins.forEach(p => { - if (p.onRegisterPlugin) { - p.onRegisterPlugin(store, (pluginKey: string, newPluginState: any) => { - const persistedState = getPersistedState( - pluginKey, - p, - store.getState().pluginStates, - ); - if (newPluginState && newPluginState !== persistedState) { - store.dispatch( - setPluginState({ - pluginKey: pluginKey, - state: newPluginState, - }), - ); - } - }); - } - }); - let state: ?State = null; store.subscribe(() => { const newState = store.getState().plugins; diff --git a/src/index.js b/src/index.js index 51ce98ca9..f75dc5d35 100644 --- a/src/index.js +++ b/src/index.js @@ -26,7 +26,7 @@ export type {Store} from './reducers/index.js'; export { default as SidebarExtensions, } from './fb-stubs/LayoutInspectorSidebarExtensions.js'; - +export {DeviceLogListener, DeviceLogEntry} from './devices/BaseDevice.js'; export {createTablePlugin} from './createTablePlugin.js'; export {default as DetailSidebar} from './chrome/DetailSidebar.js'; diff --git a/src/plugin.js b/src/plugin.js index 9027d5a6e..dc9d3aff0 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -70,8 +70,9 @@ export class FlipperBasePlugin< static getActiveNotifications: ?( persistedState: PersistedState, ) => Array; - static onRegisterPlugin: ?( + static onRegisterDevice: ?( store: Store, + baseDevice: BaseDevice, setPersistedState: ( pluginKey: string, newPluginState: ?PersistedState, diff --git a/src/plugins/crash_reporter/index.js b/src/plugins/crash_reporter/index.js index fd25cec36..2e3206195 100644 --- a/src/plugins/crash_reporter/index.js +++ b/src/plugins/crash_reporter/index.js @@ -26,7 +26,7 @@ import os from 'os'; import util from 'util'; import path from 'path'; import type {Notification} from '../../plugin'; -import type {Store} from 'flipper'; +import type {Store, DeviceLogEntry} from 'flipper'; export type Crash = {| notificationID: string, @@ -107,6 +107,7 @@ export function parseCrashLogAndUpdateState( !shouldShowCrashNotification( store.getState().connections.selectedDevice, content, + store.getState().connections.selectedDevice?.os, ) ) { return; @@ -140,7 +141,11 @@ export function parseCrashLogAndUpdateState( export function shouldShowCrashNotification( baseDevice: ?BaseDevice, content: string, + os: ?string, ): boolean { + if (os && os.includes('Android')) { + return true; + } const appPath = parsePath(content); const serial: string = baseDevice?.serial || 'unknown'; if (!appPath || !appPath.includes(serial)) { @@ -253,19 +258,6 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< return persistedState; }; - /* - * This function gets called whenever plugin is registered - */ - static onRegisterPlugin = ( - store: Store, - setPersistedState: ( - pluginKey: string, - newPluginState: ?PersistedState, - ) => void, - ): void => { - addFileWatcherForiOSCrashLogs(store, setPersistedState); - }; - static trimCallStackIfPossible = (callstack: string): string => { let regex = /Application Specific Information:/; const query = regex.exec(callstack); @@ -289,6 +281,45 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< }); }; + /* + * This function gets called whenever the device is registered + */ + static onRegisterDevice = ( + store: Store, + baseDevice: BaseDevice, + setPersistedState: ( + pluginKey: string, + newPluginState: ?PersistedState, + ) => void, + ): void => { + if (baseDevice.os.includes('iOS')) { + addFileWatcherForiOSCrashLogs(store, setPersistedState); + } else { + const referenceDate = new Date(); + (function( + store: Store, + date: Date, + setPersistedState: ( + pluginKey: string, + newPluginState: ?PersistedState, + ) => void, + ) { + baseDevice.addLogListener((entry: DeviceLogEntry) => { + if ( + entry.type === 'error' && + entry.tag === 'AndroidRuntime' && + entry.date.getTime() - date.getTime() > 0 + ) { + parseCrashLogAndUpdateState( + store, + entry.message, + setPersistedState, + ); + } + }); + })(store, referenceDate, setPersistedState); + } + }; openInLogs = (callstack: string) => { this.props.selectPlugin('DeviceLogs', callstack); }; diff --git a/src/utils/onRegisterDevice.js b/src/utils/onRegisterDevice.js new file mode 100644 index 000000000..971605f9d --- /dev/null +++ b/src/utils/onRegisterDevice.js @@ -0,0 +1,44 @@ +/** + * 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 type {Store} from '../reducers/index.js'; +import {FlipperPlugin, FlipperDevicePlugin} from '../plugin.js'; +import type BaseDevice from '../devices/BaseDevice.js'; +import {setPluginState} from '../reducers/pluginStates.js'; +import {getPersistedState} from '../utils/pluginUtils.js'; + +export function registerDeviceCallbackOnPlugins( + store: Store, + devicePlugins: Map>>, + clientPlugins: Map>>, + device: BaseDevice, +) { + const callRegisterDeviceHook = plugin => { + if (plugin.onRegisterDevice) { + plugin.onRegisterDevice( + store, + device, + (pluginKey: string, newPluginState: any) => { + const persistedState = getPersistedState( + pluginKey, + plugin, + store.getState().pluginStates, + ); + if (newPluginState && newPluginState !== persistedState) { + store.dispatch( + setPluginState({ + pluginKey, + state: newPluginState, + }), + ); + } + }, + ); + } + }; + devicePlugins.forEach(callRegisterDeviceHook); + clientPlugins.forEach(callRegisterDeviceHook); +}