@@ -153,7 +153,7 @@ class MetricsCollectionTask @Inject constructor(
153153 override fun convertAndValidateInputData (inputData : Data ) = Unit
154154
155155 private suspend fun enqueueHeartbeatUpload (
156- collectionTime : CombinedTime ,
156+ initialCollectionTime : CombinedTime ,
157157 lastHeartbeatUptime : BaseLinuxBootRelativeTime ,
158158 propertiesStore : DevicePropertiesStore ,
159159 ) {
@@ -163,16 +163,16 @@ class MetricsCollectionTask @Inject constructor(
163163 val softwareVersionChanged = customMetrics.softwareVersionChanged(deviceSoftwareVersion)
164164
165165 val batteryStatsResult = batteryStatsCollector.collect(
166- collectionTime = collectionTime ,
166+ collectionTime = initialCollectionTime ,
167167 lastHeartbeatUptime = lastHeartbeatUptime,
168168 )
169169 Logger .test(" Metrics: properties_use_service = ${metricsSettings.propertiesUseMetricService} " )
170170 Logger .test(" Metrics: software version = $heartbeatSoftwareVersion -> $deviceSoftwareVersion " )
171171
172172 // These write to Custom Metrics - do before finishing the heartbeat report.
173- storageStatsCollector.collectStorageStats(collectionTime )
173+ storageStatsCollector.collectStorageStats(initialCollectionTime )
174174 networkStatsCollector.collectAndRecord(
175- collectionTime = collectionTime ,
175+ collectionTime = initialCollectionTime ,
176176 lastHeartbeatUptime = lastHeartbeatUptime,
177177 )
178178
@@ -224,13 +224,16 @@ class MetricsCollectionTask @Inject constructor(
224224 val inMemoryMetrics = listOf (
225225 appStorageStatsCollector,
226226 databaseSizeCollector,
227- ).flatMap { collector -> collector.collect(collectionTime ) }
227+ ).flatMap { collector -> collector.collect(initialCollectionTime ) }
228228 val inMemoryHeartbeats = inMemoryMetrics.heartbeatMetrics()
229229 val inMemoryInternalHeartbeats = inMemoryMetrics.internalHeartbeatMetrics()
230- val inMemoryHrtRollups = inMemoryMetrics.hrtRollups(collectionTime )
230+ val inMemoryHrtRollups = inMemoryMetrics.hrtRollups(initialCollectionTime )
231231
232+ // Ensure that we set the "actual" collection time after all metrics have been collected, so that they will all
233+ // be included in the report.
234+ val actualCollectionTime = combinedTimeProvider.now()
232235 val heartbeatReport = customMetrics.collectHeartbeat(
233- endTimestampMs = collectionTime .timestamp.toEpochMilli(),
236+ endTimestampMs = actualCollectionTime .timestamp.toEpochMilli(),
234237 forceEndAllReports = softwareVersionChanged,
235238 )
236239
@@ -243,7 +246,7 @@ class MetricsCollectionTask @Inject constructor(
243246 .takeIf { it.isPositive() }
244247
245248 // This duration can also be negative, but it's the same as we had before.
246- val hourlyHeartbeatDurationFromUptime = collectionTime .elapsedRealtime.duration -
249+ val hourlyHeartbeatDurationFromUptime = actualCollectionTime .elapsedRealtime.duration -
247250 lastHeartbeatUptime.elapsedRealtime.duration
248251
249252 val hourlyHeartbeatDuration = hourlyHeartbeatDurationFromReport
@@ -253,15 +256,15 @@ class MetricsCollectionTask @Inject constructor(
253256 val heartbeatReportInternalMetrics = hourlyHeartbeatReport.internalMetrics
254257
255258 clientRateLimitCollector.collect(
256- collectionTime = collectionTime ,
259+ collectionTime = actualCollectionTime ,
257260 internalHeartbeatReportMetrics = heartbeatReportInternalMetrics,
258261 )
259262
260263 // If there were no heartbeat internal metrics, then fallback to include some core values.
261264 val internalMetrics = heartbeatReportInternalMetrics.ifEmpty { fallbackInternalMetrics }
262265 uploadHeartbeat(
263266 batteryStatsFile = batteryStatsResult.batteryStatsFileToUpload,
264- collectionTime = collectionTime ,
267+ collectionTime = actualCollectionTime ,
265268 heartbeatInterval = hourlyHeartbeatDuration,
266269 heartbeatReportMetrics = heartbeatReportMetrics +
267270 batteryStatsResult.aggregatedMetrics +
@@ -280,7 +283,7 @@ class MetricsCollectionTask @Inject constructor(
280283 hourlyHeartbeatReport.hrt?.let { hrtFile ->
281284 val hrtMetricsToAdd = batteryStatsResult.batteryStatsHrt +
282285 inMemoryHrtRollups +
283- propertiesStore.hrtRollups(timestampMs = collectionTime .timestamp.toEpochMilli())
286+ propertiesStore.hrtRollups(timestampMs = actualCollectionTime .timestamp.toEpochMilli())
284287 if (hrtMetricsToAdd.isNotEmpty()) {
285288 mergeHrtIntoFile(hrtFile, hrtMetricsToAdd)
286289 }
@@ -295,7 +298,7 @@ class MetricsCollectionTask @Inject constructor(
295298 heartbeatReport.dailyHeartbeatReport?.let { report ->
296299 uploadHeartbeat(
297300 batteryStatsFile = null ,
298- collectionTime = collectionTime ,
301+ collectionTime = actualCollectionTime ,
299302 heartbeatInterval = (report.endTimestampMs - report.startTimestampMs)
300303 .toDuration(MILLISECONDS ),
301304 heartbeatReportMetrics = report.metrics +
@@ -315,7 +318,7 @@ class MetricsCollectionTask @Inject constructor(
315318 .forEach { session ->
316319 uploadHeartbeat(
317320 batteryStatsFile = null ,
318- collectionTime = collectionTime ,
321+ collectionTime = actualCollectionTime ,
319322 heartbeatInterval = (session.endTimestampMs - session.startTimestampMs).toDuration(MILLISECONDS ),
320323 heartbeatReportMetrics = session.metrics,
321324 heartbeatReportInternalMetrics = session.internalMetrics,
0 commit comments