Skip to content

Commit dc11a2a

Browse files
author
Memfault Inc.
committed
Memfault BORT SDK 5.2.0 (Build 2654617)
1 parent 138e15b commit dc11a2a

File tree

218 files changed

+5729
-2951
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

218 files changed

+5729
-2951
lines changed

CHANGELOG.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,74 @@
11
# Memfault Bort Changelog
22

3+
## v5.2.0 - November 15, 2024
4+
5+
### :rocket: New Features
6+
7+
- Logs to Metrics: Bort can scan all captured log files (including those not
8+
uploaded) for patterns, and record metrics based on the results. These can be
9+
configured in the dashboard. See
10+
[documentation](https://docs.memfault.com/docs/android/android-logging#converting-logs-into-metrics).
11+
- New Core Metric for CPU usage (`cpu_usage_pct`).
12+
- New Core Metrics for memory usage (`memory_pct`, `memory_pct_max`).
13+
- New Core Metric for storage usage (`storage_used_pct`).
14+
- New Core Metrics for network Usage (`connectivity_*`). These replace the
15+
previous `network.*` metrics - those will no longer be collected, unless the
16+
`Network Usage: Collect Legacy Metrics` is enabled in the dashboard.
17+
- New Core Metrics for thermals (`thermal_*`). These replace the previous
18+
`temp.*` metrics - those will no longer be collected, unless the
19+
`Collect legacy thermal metrics` is enabled in the dashboard.
20+
- Added a `min_battery_voltage` metric to report the lowest observed voltage.
21+
- New metric to capture the battery charge cycle count
22+
(`battery.charge_cycle_count.latest`) - this only works on Android 14+. Note
23+
that the previous metric added in 4.18.0 did not work.
24+
- New metrics (`thermal_status_*`) to capture thermal mitigation status.
25+
- New HRT metric (`device-powered`) capturing device shutdown/startup events.
26+
27+
### :chart_with_upwards_trend: Improvements
28+
29+
- Update the target SDK version to 34 (Android 14).
30+
- Updated to the default hardware version (`ro.product.model`) and software
31+
version (`ro.build.version.incremental`) to match current defaults for new
32+
projects.
33+
- Improve battery use attribution (including where usage would have previously
34+
been assigned to `unknown`).
35+
- Added dashboard controls for `mar` upload job constraints (battery, charging
36+
state).
37+
- Modified sepolicy to fix some `memfault_structured_app` violations.
38+
- Removed validation of the OTA application ID being configured, if OTA is not
39+
being used (if `TARGET_USES_MFLT_OTA` is unset).
40+
- `reporting-lib-kotlin` supports asynchronous usage, when constructing a
41+
`ReportingClient`.
42+
43+
### :construction: Fixes
44+
45+
- Fixed an issue which caused `COUNT` aggregations on non-numeric metric values
46+
to always return zero. This was introduced in 4.17.0.
47+
- Fixed a bug in the SDK validation tool (`bort_cli.py`) which caused it to fail
48+
when running on Windows.
49+
- Fixed a bug where the software/hardware version and device serial sysprops
50+
would not be updated immediately if changed remotely via SDK settings (a
51+
reboot may have been required for them to take effect).
52+
- `MemfaultStructuredLogdApp` will not crash if sepolicy is incorrectly
53+
configured.
54+
- Always captured metrics for app versions/sysprops, in an edge-case where the
55+
software version sysprop changed.
56+
57+
### :house: Internal
58+
59+
- Updated mockk.
60+
- Removed bort internal log-to-disk functionality (this was not used).
61+
- Removed local storage from `DevicePropertiesStore` - forward all internal
62+
metrics using public APIs.
63+
- Bort no longer writes to the event log.
64+
- Refactored use of WorkManager.
65+
- Updated `ktlint` and reformatted some code.
66+
- Inject coroutine dispatchers in more places.
67+
- Record internal metrics for WorkManager job timing.
68+
- Fixed a flaky unit test (`DevicePropertiesStoreTest`).
69+
- Record zero values for per-app battery usage, for designated apps, instead of
70+
ignoring them (currently, Bort SDK apps only).
71+
372
## v5.1.0 - September 13, 2024
473

574
### :construction: Fixes

MemfaultDumpster/MemfaultDumpster.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ namespace {
8686
case IDumpster::CMD_ID_SET_STRUCTURED_ENABLED_PROPERTY_DISABLED: return {
8787
"/system/bin/setprop", STRUCTURED_ENABLED_PROPERTY, "0"
8888
};
89-
case IDumpster::CMD_ID_CYCLE_COUNT: return {
90-
"cat", "/sys/class/power_supply/battery/cycle_count"
89+
case IDumpster::CMD_ID_CYCLE_COUNT_NEVER_USE: return {
90+
"echo", ""
91+
};
92+
case IDumpster::CMD_ID_PROC_STAT: return {
93+
"cat", "/proc/stat"
9194
};
92-
9395

9496
default: return {};
9597
}

MemfaultDumpster/com/memfault/dumpster/IDumpster.aidl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ interface IDumpster {
99
const int VERSION_GETPROP_TYPES = 3;
1010
const int VERSION_BORT_CONTINUOUS_LOGGING = 4;
1111
const int VERSION_BORT_CONTINUOUS_FIXES = 5;
12-
const int VERSION_CYCLE_COUNT = 6;
12+
const int VERSION_CYCLE_COUNT_NEVER_USE = 6;
13+
const int VERSION_PROC_STAT = 7;
14+
const int VERSION_CYCLE_COUNT_REMOVED = 6;
1315

1416
/**
1517
* Current version of the service.
1618
*/
17-
const int VERSION = 6;
19+
const int VERSION = 8;
1820

1921
/**
2022
* Gets the version of the MemfaultDumpster service.
@@ -27,7 +29,8 @@ interface IDumpster {
2729
const int CMD_ID_SET_STRUCTURED_ENABLED_PROPERTY_ENABLED = 4;
2830
const int CMD_ID_SET_STRUCTURED_ENABLED_PROPERTY_DISABLED = 5;
2931
const int CMD_ID_GETPROP_TYPES = 6;
30-
const int CMD_ID_CYCLE_COUNT = 7;
32+
const int CMD_ID_CYCLE_COUNT_NEVER_USE = 7;
33+
const int CMD_ID_PROC_STAT = 8;
3134

3235
/**
3336
* Runs a basic command and calls the listener with the string output.

MemfaultPackages/.editorconfig

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ ij_java_line_comment_add_space_on_reformat = false
137137
ij_java_line_comment_at_first_column = false
138138
ij_java_method_annotation_wrap = normal
139139
ij_java_method_brace_style = end_of_line
140-
ij_java_method_call_chain_wrap = on_every_item
140+
ij_java_method_call_chain_wrap = normal
141141
ij_java_method_parameters_new_line_after_left_paren = false
142142
ij_java_method_parameters_right_paren_on_new_line = false
143143
ij_java_method_parameters_wrap = normal
@@ -262,7 +262,7 @@ ij_java_wrap_first_method_in_call_chain = false
262262
ij_java_wrap_long_lines = false
263263

264264
[{*.kt,*.kts}]
265-
ktlint_code_style = android
265+
ktlint_code_style = android_studio
266266
indent_size = 4
267267
tab_width = 4
268268
ij_kotlin_align_in_columns_case_branch = false
@@ -313,10 +313,10 @@ ij_kotlin_line_comment_add_space = true
313313
ij_kotlin_line_comment_add_space_on_reformat = false
314314
ij_kotlin_line_comment_at_first_column = false
315315
ij_kotlin_method_annotation_wrap = normal
316-
ij_kotlin_method_call_chain_wrap = on_every_item
316+
ij_kotlin_method_call_chain_wrap = normal
317317
ij_kotlin_method_parameters_new_line_after_left_paren = true
318318
ij_kotlin_method_parameters_right_paren_on_new_line = true
319-
ij_kotlin_method_parameters_wrap = split_into_lines
319+
ij_kotlin_method_parameters_wrap = normal
320320
ij_kotlin_name_count_to_use_star_import = 2147483647
321321
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
322322
ij_kotlin_parameter_annotation_wrap = off
@@ -351,4 +351,9 @@ ij_kotlin_wrap_first_method_in_call_chain = false
351351
# _____ KTLINT RULES BELOW _____
352352
insert_final_newline = true
353353
max_line_length = 120
354+
ktlint_standard_class-signature = disabled
355+
ktlint_standard_function-signature = disabled
356+
ktlint_standard_multiline-expression-wrapping = disabled
354357
ktlint_standard_package-name = disabled
358+
ktlint_standard_property-naming = disabled
359+
ktlint_function_signature_body_expression_wrapping = multiline
Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,6 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
xmlns:tools="http://schemas.android.com/tools">
33

4-
<!-- Allows for connectivity checks-->
5-
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
6-
<application>
7-
<receiver android:name=".BootCompleteReceiver">
8-
<intent-filter>
9-
<action android:name="android.intent.action.BOOT_COMPLETED" />
10-
<action android:name="com.memfault.intent.action.OTA_SETTINGS_CHANGED" />
11-
</intent-filter>
12-
</receiver>
13-
14-
<receiver
15-
android:name=".CheckForUpdatesReceiver"
16-
android:permission="${bortControlPermission}">
17-
<intent-filter>
18-
<action android:name="com.memfault.intent.action.OTA_CHECK_FOR_UPDATES" />
19-
</intent-filter>
20-
</receiver>
21-
22-
<receiver
23-
android:name=".ShellCheckForUpdatesReceiver"
24-
android:permission="android.permission.DUMP">
25-
<intent-filter>
26-
<action android:name="com.memfault.intent.action.OTA_CHECK_FOR_UPDATES_SHELL" />
27-
</intent-filter>
28-
</receiver>
29-
30-
<service android:name=".download.DownloadOtaService" />
31-
</application>
324
<!-- Allows writing recovery-based OTA to /data/ota_package -->
335
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
346
<!-- Allows the download service to work in the foreground -->
@@ -58,4 +30,48 @@
5830
<uses-permission
5931
android:name="android.permission.RECOVERY"
6032
tools:ignore="ProtectedPermissions" />
33+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
34+
<!-- Allows for connectivity checks-->
35+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
36+
37+
<application>
38+
<receiver android:name=".BootCompleteReceiver"
39+
android:exported="true">
40+
<intent-filter>
41+
<action android:name="android.intent.action.BOOT_COMPLETED" />
42+
<action android:name="com.memfault.intent.action.OTA_SETTINGS_CHANGED" />
43+
</intent-filter>
44+
</receiver>
45+
46+
<receiver
47+
android:name=".CheckForUpdatesReceiver"
48+
android:permission="${bortControlPermission}"
49+
android:exported="true">
50+
<intent-filter>
51+
<action android:name="com.memfault.intent.action.OTA_CHECK_FOR_UPDATES" />
52+
</intent-filter>
53+
</receiver>
54+
55+
<receiver
56+
android:name=".ShellCheckForUpdatesReceiver"
57+
android:permission="android.permission.DUMP"
58+
android:exported="true">
59+
<intent-filter>
60+
<action android:name="com.memfault.intent.action.OTA_CHECK_FOR_UPDATES_SHELL" />
61+
</intent-filter>
62+
</receiver>
63+
64+
<service android:name=".download.DownloadOtaService" android:foregroundServiceType="specialUse">
65+
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
66+
android:value="OTA Download"/>
67+
</service>
68+
69+
<service
70+
android:name="androidx.work.impl.foreground.SystemForegroundService"
71+
android:foregroundServiceType="specialUse"
72+
tools:node="merge" >
73+
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
74+
android:value="OTA Download"/>
75+
</service>
76+
</application>
6177
</manifest>

MemfaultPackages/bort-ota-lib/src/main/java/com/memfault/bort/ota/lib/ABUpdateActionHandler.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ import android.os.PowerManager
66
import android.os.UpdateEngine
77
import android.os.UpdateEngineCallback
88
import android.util.Log
9+
import com.memfault.bort.Default
910
import com.memfault.bort.shared.BortSharedJson
1011
import com.memfault.bort.shared.BuildConfig
1112
import com.memfault.bort.shared.Logger
1213
import com.memfault.bort.shared.PreferenceKeyProvider
1314
import com.squareup.anvil.annotations.ContributesBinding
1415
import dagger.hilt.components.SingletonComponent
1516
import kotlinx.coroutines.CoroutineScope
16-
import kotlinx.coroutines.Dispatchers
1717
import kotlinx.coroutines.launch
1818
import javax.inject.Inject
1919
import javax.inject.Singleton
20+
import kotlin.coroutines.CoroutineContext
2021

2122
fun interface RebootDevice : () -> Unit
2223

@@ -41,12 +42,13 @@ class ABUpdateActionHandler @Inject constructor(
4142
private val otaRulesProvider: OtaRulesProvider,
4243
private val softwareUpdateChecker: SoftwareUpdateChecker,
4344
private val settingsProvider: SoftwareUpdateSettingsProvider,
45+
@Default private val defaultCoroutineContext: CoroutineContext,
4446
) : UpdateActionHandler {
4547
override fun initialize() {
4648
androidUpdateEngine.bind(object : AndroidUpdateEngineCallback {
4749
override fun onStatusUpdate(status: Int, percent: Float) {
4850
Logger.d("onStatusUpdate: status=$status percent=$percent")
49-
CoroutineScope(Dispatchers.Default).launch {
51+
CoroutineScope(defaultCoroutineContext).launch {
5052
when (status) {
5153
UPDATE_ENGINE_STATUS_DOWNLOADING -> {
5254
val cachedOta = cachedOtaProvider.get()
@@ -101,7 +103,7 @@ class ABUpdateActionHandler @Inject constructor(
101103

102104
override fun onPayloadApplicationComplete(errorCode: Int) {
103105
Logger.d("onPayloadApplicationComplete: errorCode=$errorCode")
104-
CoroutineScope(Dispatchers.Default).launch {
106+
CoroutineScope(defaultCoroutineContext).launch {
105107
when (errorCode) {
106108
UPDATE_ENGINE_ERROR_SUCCESS -> {}
107109
UPDATE_ENGINE_ERROR_DOWNLOAD_TRANSFER_ERROR ->

MemfaultPackages/bort-ota-lib/src/main/java/com/memfault/bort/ota/lib/OtaDownloadWorker.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.memfault.bort.ota.lib
22

33
import android.content.Context
4+
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
45
import androidx.annotation.VisibleForTesting
56
import androidx.hilt.work.HiltWorker
67
import androidx.work.BackoffPolicy
@@ -60,7 +61,7 @@ class OtaDownloadWorker @AssistedInject constructor(
6061
if (progressPercentage != lastReportedPercentage) {
6162
val builder = setupForegroundNotification(applicationContext)
6263
builder.setProgress(100, progressPercentage, false)
63-
val foregroundInfo = ForegroundInfo(NOTIFICATION_ID, builder.build())
64+
val foregroundInfo = ForegroundInfo(NOTIFICATION_ID, builder.build(), FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
6465
setForeground(foregroundInfo)
6566
lastReportedPercentage = progressPercentage
6667
}

MemfaultPackages/bort-ota-lib/src/main/java/com/memfault/bort/ota/lib/PeriodicSoftwareUpdateWorker.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import androidx.work.NetworkType
99
import androidx.work.PeriodicWorkRequestBuilder
1010
import androidx.work.WorkManager
1111
import androidx.work.WorkerParameters
12-
import com.memfault.bort.DEV_MODE_DISABLED
12+
import com.memfault.bort.DevModeDisabled
1313
import com.memfault.bort.shared.JitterDelayProvider
1414
import com.memfault.bort.shared.Logger
1515
import com.memfault.bort.shared.NoOpJobReporter
@@ -54,7 +54,7 @@ class PeriodicSoftwareUpdateWorker @AssistedInject constructor(
5454
setInitialDelay(
5555
JitterDelayProvider(
5656
jitterDelayConfiguration = { JitterDelayProvider.ApplyJitter.APPLY },
57-
devMode = DEV_MODE_DISABLED,
57+
devMode = DevModeDisabled,
5858
).randomJitterDelay().toJavaDuration(),
5959
)
6060
}.build()

MemfaultPackages/bort-ota-lib/src/main/java/com/memfault/bort/ota/lib/RecoveryBasedUpdateActionHandler.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.memfault.bort.ota.lib
22

33
import android.app.Application
44
import android.os.RecoverySystem
5+
import com.memfault.bort.IO
56
import com.memfault.bort.ota.lib.download.DownloadOtaService
67
import com.memfault.bort.shared.BuildConfig
78
import com.memfault.bort.shared.InternalMetric
@@ -11,13 +12,11 @@ import com.memfault.bort.shared.InternalMetric.Companion.OTA_INSTALL_RECOVERY_VE
1112
import com.memfault.bort.shared.Logger
1213
import com.squareup.anvil.annotations.ContributesBinding
1314
import dagger.hilt.components.SingletonComponent
14-
import kotlinx.coroutines.CoroutineDispatcher
15-
import kotlinx.coroutines.Dispatchers
16-
import kotlinx.coroutines.ExperimentalCoroutinesApi
1715
import kotlinx.coroutines.suspendCancellableCoroutine
1816
import kotlinx.coroutines.withContext
1917
import java.io.File
2018
import javax.inject.Inject
19+
import kotlin.coroutines.CoroutineContext
2120

2221
/**
2322
* This interface abstracts recovery interactions. On real devices, the RealRecoveryInterface will use RecoverySystem
@@ -47,7 +46,7 @@ class RealStartUpdatedownload @Inject constructor(
4746
* 3) Verifying the update package
4847
* 4) Install the update package
4948
*/
50-
@OptIn(ExperimentalCoroutinesApi::class)
49+
5150
class RecoveryBasedUpdateActionHandler @Inject constructor(
5251
private val recoveryInterface: RecoveryInterface,
5352
private val startUpdateDownload: StartUpdateDownload,
@@ -58,6 +57,7 @@ class RecoveryBasedUpdateActionHandler @Inject constructor(
5857
private val application: Application,
5958
private val otaRulesProvider: OtaRulesProvider,
6059
private val settingsProvider: SoftwareUpdateSettingsProvider,
60+
@IO private val ioCoroutineContext: CoroutineContext,
6161
) : UpdateActionHandler {
6262
override fun initialize() = Unit
6363

@@ -157,7 +157,7 @@ class RecoveryBasedUpdateActionHandler @Inject constructor(
157157
}
158158

159159
private suspend fun installUpdate(updatePath: File): Boolean =
160-
withContext(Dispatchers.IO) {
160+
withContext(ioCoroutineContext) {
161161
suspendCancellableCoroutine { continuation ->
162162
try {
163163
metricLogger.addMetric(InternalMetric(OTA_INSTALL_RECOVERY, synchronous = true))
@@ -176,8 +176,7 @@ class RecoveryBasedUpdateActionHandler @Inject constructor(
176176

177177
private suspend fun verifyUpdate(
178178
updateFile: File,
179-
dispatcher: CoroutineDispatcher = Dispatchers.IO,
180-
) = withContext(dispatcher) {
179+
) = withContext(ioCoroutineContext) {
181180
suspendCancellableCoroutine<Boolean> { continuation ->
182181
try {
183182
recoveryInterface.verifyOrThrow(updateFile)

MemfaultPackages/bort-ota-lib/src/main/java/com/memfault/bort/ota/lib/SoftwareUpdateChecker.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.memfault.cloud.sdk.MemfaultDeviceInfo
1212
import com.memfault.cloud.sdk.MemfaultOtaPackage
1313
import com.squareup.anvil.annotations.ContributesBinding
1414
import dagger.hilt.components.SingletonComponent
15-
import kotlinx.coroutines.ExperimentalCoroutinesApi
1615
import kotlinx.coroutines.suspendCancellableCoroutine
1716
import kotlinx.serialization.SerialName
1817
import kotlinx.serialization.Serializable
@@ -38,7 +37,6 @@ interface SoftwareUpdateChecker {
3837
suspend fun getLatestRelease(): Ota?
3938
}
4039

41-
@OptIn(ExperimentalCoroutinesApi::class)
4240
@ContributesBinding(SingletonComponent::class)
4341
class MemfaultSoftwareUpdateChecker @Inject constructor(
4442
private val memfault: MemfaultCloud,

0 commit comments

Comments
 (0)