Skip to content

Commit 96a4cf1

Browse files
authored
Merge pull request #4247 from Expensify/marcaaron-androidStartup
Add more Firebase performance tracing. Improve Android boot time.
2 parents b964c89 + c687d63 commit 96a4cf1

File tree

12 files changed

+149
-5
lines changed

12 files changed

+149
-5
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default () => {};

src/CONST.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Expensify.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Onyx.init({
3737
[ONYXKEYS.IOU]: {
3838
loading: false, error: false, creatingIOUTransaction: false, isRetrievingCurrency: false,
3939
},
40+
[ONYXKEYS.IS_SIDEBAR_LOADED]: false,
4041
},
4142
registerStorageEventListener: (onStorageEvent) => {
4243
listenToStorageEvents(onStorageEvent);
@@ -72,6 +73,9 @@ const propTypes = {
7273
/** Whether the initial data needed to render the app is ready */
7374
initialReportDataLoaded: PropTypes.bool,
7475

76+
/** Tells us if the sidebar has rendered */
77+
isSidebarLoaded: PropTypes.bool,
78+
7579
/** List of betas */
7680
betas: PropTypes.arrayOf(PropTypes.string),
7781
};
@@ -84,6 +88,7 @@ const defaultProps = {
8488
},
8589
updateAvailable: false,
8690
initialReportDataLoaded: false,
91+
isSidebarLoaded: false,
8792
betas: [],
8893
};
8994

@@ -144,7 +149,7 @@ class Expensify extends PureComponent {
144149
Navigation.navigate(ROUTES.WORKSPACE_NEW);
145150
}
146151

147-
if (this.getAuthToken() && this.props.initialReportDataLoaded) {
152+
if (this.getAuthToken() && this.props.initialReportDataLoaded && this.props.isSidebarLoaded) {
148153
BootSplash.getVisibilityStatus()
149154
.then((value) => {
150155
if (value !== 'visible') {
@@ -208,4 +213,7 @@ export default withOnyx({
208213
initialReportDataLoaded: {
209214
key: ONYXKEYS.INITIAL_REPORT_DATA_LOADED,
210215
},
216+
isSidebarLoaded: {
217+
key: ONYXKEYS.IS_SIDEBAR_LOADED,
218+
},
211219
})(Expensify);

src/ONYXKEYS.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ export default {
1616
// Boolean flag set whenever we are waiting for the reconnection callbacks to finish.
1717
IS_LOADING_AFTER_RECONNECT: 'isLoadingAfterReconnect',
1818

19+
// Boolean flag set whenever the sidebar has loaded
20+
IS_SIDEBAR_LOADED: 'isSidebarLoaded',
21+
1922
NETWORK_REQUEST_QUEUE: 'networkRequestQueue',
2023

2124
// What the active route is for our navigator. Global route that determines what views to display.

src/components/OptionsList.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ const propTypes = {
7878

7979
/** Whether to disable the interactivity of the list's option row(s) */
8080
disableRowInteractivity: PropTypes.bool,
81+
82+
/** Callback to execute when the SectionList lays out */
83+
onLayout: PropTypes.func,
8184
};
8285

8386
const defaultProps = {
@@ -99,6 +102,7 @@ const defaultProps = {
99102
showTitleTooltip: false,
100103
optionMode: undefined,
101104
disableRowInteractivity: false,
105+
onLayout: undefined,
102106
};
103107

104108
class OptionsList extends Component {
@@ -109,6 +113,8 @@ class OptionsList extends Component {
109113
this.renderSectionHeader = this.renderSectionHeader.bind(this);
110114
this.extractKey = this.extractKey.bind(this);
111115
this.onScrollToIndexFailed = this.onScrollToIndexFailed.bind(this);
116+
this.viewabilityConfig = {viewAreaCoveragePercentThreshold: 95};
117+
this.didLayout = false;
112118
}
113119

114120
shouldComponentUpdate(nextProps) {
@@ -228,6 +234,18 @@ class OptionsList extends Component {
228234
renderItem={this.renderItem}
229235
renderSectionHeader={this.renderSectionHeader}
230236
extraData={this.props.focusedIndex}
237+
initialNumToRender={5}
238+
maxToRenderPerBatch={5}
239+
windowSize={5}
240+
viewabilityConfig={this.viewabilityConfig}
241+
onViewableItemsChanged={() => {
242+
if (this.didLayout) {
243+
return;
244+
}
245+
246+
this.didLayout = true;
247+
this.props.onLayout();
248+
}}
231249
/>
232250
</View>
233251
);

src/libs/Firebase/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** Web does not use Firebase for performance tracing */
2+
3+
export default {
4+
startTrace() {},
5+
stopTrace() {},
6+
};

src/libs/Firebase/index.native.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* eslint-disable no-unused-vars */
2+
import perf from '@react-native-firebase/perf';
3+
import {isDevelopment} from '../Environment/Environment';
4+
import Log from '../Log';
5+
6+
const traceMap = {};
7+
8+
/**
9+
* @param {String} customEventName
10+
*/
11+
function startTrace(customEventName) {
12+
const start = global.performance.now();
13+
if (isDevelopment()) {
14+
return;
15+
}
16+
17+
if (traceMap[customEventName]) {
18+
return;
19+
}
20+
21+
perf().startTrace(customEventName)
22+
.then((trace) => {
23+
traceMap[customEventName] = {
24+
trace,
25+
start,
26+
};
27+
});
28+
}
29+
30+
/**
31+
* @param {String} customEventName
32+
*/
33+
function stopTrace(customEventName) {
34+
const stop = global.performance.now();
35+
36+
if (isDevelopment()) {
37+
return;
38+
}
39+
40+
const {trace, start} = traceMap[customEventName];
41+
if (!trace) {
42+
return;
43+
}
44+
45+
trace.stop();
46+
47+
// Uncomment to inspect logs on release builds
48+
// Log.info(`sidebar_loaded: ${stop - start} ms`, true);
49+
50+
delete traceMap[customEventName];
51+
}
52+
53+
export default {
54+
startTrace,
55+
stopTrace,
56+
};

src/libs/actions/App.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import Onyx from 'react-native-onyx';
22
import ONYXKEYS from '../../ONYXKEYS';
33
import * as API from '../API';
4+
import Firebase from '../Firebase';
5+
import CONST from '../../CONST';
6+
7+
let isSidebarLoaded;
8+
9+
Onyx.connect({
10+
key: ONYXKEYS.IS_SIDEBAR_LOADED,
11+
callback: val => isSidebarLoaded = val,
12+
initWithStoredValues: false,
13+
});
414

515
/**
616
* @param {String} url
@@ -17,7 +27,17 @@ function setLocale(locale) {
1727
Onyx.merge(ONYXKEYS.NVP_PREFERRED_LOCALE, locale);
1828
}
1929

30+
function setSidebarLoaded() {
31+
if (isSidebarLoaded) {
32+
return;
33+
}
34+
35+
Onyx.set(ONYXKEYS.IS_SIDEBAR_LOADED, true);
36+
Firebase.stopTrace(CONST.TIMING.SIDEBAR_LOADED);
37+
}
38+
2039
export {
2140
setCurrentURL,
2241
setLocale,
42+
setSidebarLoaded,
2343
};

src/libs/actions/Timing.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import getPlatform from '../getPlatform';
22
import {Graphite_Timer} from '../API';
3+
import {isDevelopment} from '../Environment/Environment';
34

45
let timestampData = {};
56

@@ -26,14 +27,19 @@ function end(eventName, secondaryName = '') {
2627
: `expensify.cash.${eventName}`;
2728

2829
console.debug(`Timing:${grafanaEventName}`, eventTime);
30+
delete timestampData[eventName];
31+
32+
// eslint-disable-next-line no-undef
33+
if (isDevelopment()) {
34+
// Don't create traces on dev as this will mess up the accuracy of data in release builds of the app
35+
return;
36+
}
2937

3038
Graphite_Timer({
3139
name: grafanaEventName,
3240
value: eventTime,
3341
platform: `${getPlatform()}`,
3442
});
35-
36-
delete timestampData[eventName];
3743
}
3844
}
3945

src/pages/home/ReportScreen.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import {withOnyx} from 'react-native-onyx';
23
import PropTypes from 'prop-types';
34
import styles from '../../styles/styles';
45
import ReportView from './report/ReportView';
@@ -8,6 +9,7 @@ import Navigation from '../../libs/Navigation/Navigation';
89
import ROUTES from '../../ROUTES';
910
import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
1011
import {updateCurrentlyViewedReportID} from '../../libs/actions/Report';
12+
import ONYXKEYS from '../../ONYXKEYS';
1113

1214
const propTypes = {
1315
/** Navigation route context info provided by react navigation */
@@ -18,6 +20,13 @@ const propTypes = {
1820
reportID: PropTypes.string,
1921
}).isRequired,
2022
}).isRequired,
23+
24+
/** Tells us if the sidebar has rendered */
25+
isSidebarLoaded: PropTypes.bool,
26+
};
27+
28+
const defaultProps = {
29+
isSidebarLoaded: false,
2130
};
2231

2332
class ReportScreen extends React.Component {
@@ -84,6 +93,10 @@ class ReportScreen extends React.Component {
8493
}
8594

8695
render() {
96+
if (!this.props.isSidebarLoaded) {
97+
return null;
98+
}
99+
87100
return (
88101
<ScreenWrapper style={[styles.appContent, styles.flex1]}>
89102
<HeaderView
@@ -100,4 +113,10 @@ class ReportScreen extends React.Component {
100113
}
101114

102115
ReportScreen.propTypes = propTypes;
103-
export default ReportScreen;
116+
ReportScreen.defaultProps = defaultProps;
117+
118+
export default withOnyx({
119+
isSidebarLoaded: {
120+
key: ONYXKEYS.IS_SIDEBAR_LOADED,
121+
},
122+
})(ReportScreen);

src/pages/home/sidebar/SidebarLinks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import CONST from '../../../CONST';
2020
import {participantPropTypes} from './optionPropTypes';
2121
import themeColors from '../../../styles/themes/default';
2222
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
23-
23+
import * as App from '../../../libs/actions/App';
2424

2525
const propTypes = {
2626
/** Toggles the navigation menu open and closed */
@@ -179,6 +179,7 @@ class SidebarLinks extends React.Component {
179179
showTitleTooltip
180180
disableFocusOptions={this.props.isSmallScreenWidth}
181181
optionMode={this.props.priorityMode === CONST.PRIORITY_MODE.GSD ? 'compact' : 'default'}
182+
onLayout={App.setSidebarLoaded}
182183
/>
183184
<KeyboardSpacer />
184185
</View>

src/pages/home/sidebar/SidebarScreen.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from '../../../components/Icon/Expensicons';
2424
import Permissions from '../../../libs/Permissions';
2525
import ONYXKEYS from '../../../ONYXKEYS';
26+
import Firebase from '../../../libs/Firebase';
2627

2728
const propTypes = {
2829
/** Beta features list */
@@ -47,6 +48,10 @@ class SidebarScreen extends Component {
4748
};
4849
}
4950

51+
componentDidMount() {
52+
Firebase.startTrace(CONST.TIMING.SIDEBAR_LOADED);
53+
}
54+
5055
/**
5156
* Method called when a Create Menu item is selected.
5257
*/

0 commit comments

Comments
 (0)