25
25
import com .google .android .gms .common .util .VisibleForTesting ;
26
26
import com .google .firebase .perf .logging .AndroidLogger ;
27
27
import com .google .firebase .perf .provider .FirebasePerfProvider ;
28
+ import com .google .firebase .perf .session .PerfSession ;
28
29
import com .google .firebase .perf .session .SessionManager ;
29
30
import com .google .firebase .perf .transport .TransportManager ;
30
31
import com .google .firebase .perf .util .Clock ;
35
36
import java .lang .ref .WeakReference ;
36
37
import java .util .ArrayList ;
37
38
import java .util .List ;
39
+ import java .util .concurrent .ExecutorService ;
40
+ import java .util .concurrent .LinkedBlockingQueue ;
41
+ import java .util .concurrent .ThreadPoolExecutor ;
38
42
import java .util .concurrent .TimeUnit ;
39
43
40
44
/**
@@ -55,7 +59,39 @@ public class AppStartTrace implements ActivityLifecycleCallbacks {
55
59
56
60
private static final long MAX_LATENCY_BEFORE_UI_INIT = TimeUnit .MINUTES .toMicros (1 );
57
61
62
+ // Core pool size 0 allows threads to shut down if they're idle
63
+ private static final int CORE_POOL_SIZE = 0 ;
64
+ private static final int MAX_POOL_SIZE = 1 ; // Only need single thread
65
+
58
66
private static volatile AppStartTrace instance ;
67
+ private static ExecutorService executorService ;
68
+
69
+ private boolean isRegisteredForLifecycleCallbacks = false ;
70
+ private final TransportManager transportManager ;
71
+ private final Clock clock ;
72
+ private Context appContext ;
73
+ /**
74
+ * The first time onCreate() of any activity is called, the activity is saved as launchActivity.
75
+ */
76
+ private WeakReference <Activity > launchActivity ;
77
+ /**
78
+ * The first time onResume() of any activity is called, the activity is saved as appStartActivity
79
+ */
80
+ private WeakReference <Activity > appStartActivity ;
81
+
82
+ /**
83
+ * If the time difference between app starts and creation of any Activity is larger than
84
+ * MAX_LATENCY_BEFORE_UI_INIT, set mTooLateToInitUI to true and we don't send AppStart Trace.
85
+ */
86
+ private boolean isTooLateToInitUI = false ;
87
+
88
+ private Timer appStartTime = null ;
89
+ private Timer onCreateTime = null ;
90
+ private Timer onStartTime = null ;
91
+ private Timer onResumeTime = null ;
92
+
93
+ private PerfSession startSession ;
94
+ private boolean isStartedFromBackground = false ;
59
95
60
96
/**
61
97
* Called from onCreate() method of an activity by instrumented byte code.
@@ -94,41 +130,29 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock)
94
130
if (instance == null ) {
95
131
synchronized (AppStartTrace .class ) {
96
132
if (instance == null ) {
97
- instance = new AppStartTrace (transportManager , clock );
133
+ instance =
134
+ new AppStartTrace (
135
+ transportManager ,
136
+ clock ,
137
+ new ThreadPoolExecutor (
138
+ CORE_POOL_SIZE ,
139
+ MAX_POOL_SIZE ,
140
+ /* keepAliveTime= */ MAX_LATENCY_BEFORE_UI_INIT + 10 ,
141
+ TimeUnit .SECONDS ,
142
+ new LinkedBlockingQueue <>(1 )));
98
143
}
99
144
}
100
145
}
101
146
return instance ;
102
147
}
103
148
104
- private boolean isRegisteredForLifecycleCallbacks = false ;
105
- private final TransportManager transportManager ;
106
- private final Clock clock ;
107
- private Context appContext ;
108
- /**
109
- * The first time onCreate() of any activity is called, the activity is saved as launchActivity.
110
- */
111
- private WeakReference <Activity > launchActivity ;
112
- /**
113
- * The first time onResume() of any activity is called, the activity is saved as appStartActivity
114
- */
115
- private WeakReference <Activity > appStartActivity ;
116
-
117
- /**
118
- * If the time difference between app starts and creation of any Activity is larger than
119
- * MAX_LATENCY_BEFORE_UI_INIT, set mTooLateToInitUI to true and we don't send AppStart Trace.
120
- */
121
- private boolean isTooLateToInitUI = false ;
122
-
123
- private Timer onCreateTime = null ;
124
- private Timer onStartTime = null ;
125
- private Timer onResumeTime = null ;
126
-
127
- private boolean isStartedFromBackground = false ;
128
-
129
- AppStartTrace (@ NonNull TransportManager transportManager , @ NonNull Clock clock ) {
149
+ AppStartTrace (
150
+ @ NonNull TransportManager transportManager ,
151
+ @ NonNull Clock clock ,
152
+ @ NonNull ExecutorService executorService ) {
130
153
this .transportManager = transportManager ;
131
154
this .clock = clock ;
155
+ this .executorService = executorService ;
132
156
}
133
157
134
158
/** Called from FirebasePerfProvider to register this callback. */
@@ -191,51 +215,57 @@ public synchronized void onActivityResumed(Activity activity) {
191
215
appStartActivity = new WeakReference <Activity >(activity );
192
216
193
217
onResumeTime = clock .getTime ();
194
- final Timer startTime = FirebasePerfProvider .getAppStartTime ();
218
+ this .appStartTime = FirebasePerfProvider .getAppStartTime ();
219
+ this .startSession = SessionManager .getInstance ().perfSession ();
195
220
AndroidLogger .getInstance ()
196
221
.debug (
197
222
"onResume(): "
198
223
+ activity .getClass ().getName ()
199
224
+ ": "
200
- + startTime .getDurationMicros (onResumeTime )
225
+ + this . appStartTime .getDurationMicros (onResumeTime )
201
226
+ " microseconds" );
202
227
228
+ // Log the app start trace in a non-main thread.
229
+ executorService .execute (this ::logAppStartTrace );
230
+
231
+ if (isRegisteredForLifecycleCallbacks ) {
232
+ // After AppStart trace is logged, we can unregister this callback.
233
+ unregisterActivityLifecycleCallbacks ();
234
+ }
235
+ }
236
+
237
+ private void logAppStartTrace () {
203
238
TraceMetric .Builder metric =
204
239
TraceMetric .newBuilder ()
205
240
.setName (Constants .TraceNames .APP_START_TRACE_NAME .toString ())
206
- .setClientStartTimeUs (startTime .getMicros ())
207
- .setDurationUs (startTime .getDurationMicros (onResumeTime ));
241
+ .setClientStartTimeUs (getappStartTime () .getMicros ())
242
+ .setDurationUs (getappStartTime () .getDurationMicros (onResumeTime ));
208
243
List <TraceMetric > subtraces = new ArrayList <>(/* initialCapacity= */ 3 );
209
244
210
- TraceMetric .Builder temp =
245
+ TraceMetric .Builder traceMetricBuilder =
211
246
TraceMetric .newBuilder ()
212
247
.setName (Constants .TraceNames .ON_CREATE_TRACE_NAME .toString ())
213
- .setClientStartTimeUs (startTime .getMicros ())
214
- .setDurationUs (startTime .getDurationMicros (onCreateTime ));
215
- subtraces .add (temp .build ());
248
+ .setClientStartTimeUs (getappStartTime () .getMicros ())
249
+ .setDurationUs (getappStartTime () .getDurationMicros (onCreateTime ));
250
+ subtraces .add (traceMetricBuilder .build ());
216
251
217
- temp = TraceMetric .newBuilder ();
218
- temp .setName (Constants .TraceNames .ON_START_TRACE_NAME .toString ())
252
+ traceMetricBuilder = TraceMetric .newBuilder ();
253
+ traceMetricBuilder
254
+ .setName (Constants .TraceNames .ON_START_TRACE_NAME .toString ())
219
255
.setClientStartTimeUs (onCreateTime .getMicros ())
220
256
.setDurationUs (onCreateTime .getDurationMicros (onStartTime ));
221
- subtraces .add (temp .build ());
257
+ subtraces .add (traceMetricBuilder .build ());
222
258
223
- temp = TraceMetric .newBuilder ();
224
- temp .setName (Constants .TraceNames .ON_RESUME_TRACE_NAME .toString ())
259
+ traceMetricBuilder = TraceMetric .newBuilder ();
260
+ traceMetricBuilder
261
+ .setName (Constants .TraceNames .ON_RESUME_TRACE_NAME .toString ())
225
262
.setClientStartTimeUs (onStartTime .getMicros ())
226
263
.setDurationUs (onStartTime .getDurationMicros (onResumeTime ));
227
- subtraces .add (temp .build ());
264
+ subtraces .add (traceMetricBuilder .build ());
228
265
229
- metric
230
- .addAllSubtraces (subtraces )
231
- .addPerfSessions (SessionManager .getInstance ().perfSession ().build ());
266
+ metric .addAllSubtraces (subtraces ).addPerfSessions (this .startSession .build ());
232
267
233
268
transportManager .log (metric .build (), ApplicationProcessState .FOREGROUND_BACKGROUND );
234
-
235
- if (isRegisteredForLifecycleCallbacks ) {
236
- // After AppStart trace is logged, we can unregister this callback.
237
- unregisterActivityLifecycleCallbacks ();
238
- }
239
269
}
240
270
241
271
@ Override
@@ -285,6 +315,11 @@ Activity getAppStartActivity() {
285
315
return appStartActivity .get ();
286
316
}
287
317
318
+ @ VisibleForTesting
319
+ Timer getappStartTime () {
320
+ return appStartTime ;
321
+ }
322
+
288
323
@ VisibleForTesting
289
324
Timer getOnCreateTime () {
290
325
return onCreateTime ;
0 commit comments