Skip to content

Commit f16fde1

Browse files
author
Memfault Inc.
committed
Memfault BORT SDK 5.3.0 (Build 2885152)
1 parent dc11a2a commit f16fde1

File tree

154 files changed

+3021
-1646
lines changed

Some content is hidden

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

154 files changed

+3021
-1646
lines changed

CHANGELOG.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,58 @@
1-
# Memfault Bort Changelog
1+
# Memfault Android SDK Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6+
This project currently does not attempt to adhere to Semantic Versioning, but
7+
breaking changes are avoided unless absolutely necessary.
8+
9+
## v5.3.0 - February 14, 2025
10+
11+
### :rocket: New Features
12+
13+
- Added new per-component total storage metrics. The total storage used
14+
(apps+cache+data+external) by an application can be recorded as a
15+
`storage_<package>_bytes` metric. Please feel free to contact us if you would
16+
like this enabled for applications in your project.
17+
- Added new mechanism to group operational crashes by package. The existing
18+
`operational_crashes` core metric can be divided into
19+
`operational_crashes_<group>` metrics, based off of the package names of the
20+
crashes. Please feel free to contact us if you would like this enabled for
21+
your project.
22+
- Added new DropBox count core metrics. The number of DropBox entries processed
23+
each heartbeat, grouped by Issue type, is now recorded as a
24+
`drop_box_<type>_count` metric. This makes identifying crashy devices even
25+
easier.
26+
- Added new `.mean_time_in_state` metric alongside `.total_secs` when the
27+
`TIME_TOTALS` aggregation is used with `StateTracker`s. The existing
28+
`.total_secs` metric is truncated between heartbeats, so it is only useful as
29+
a rough percentage comparison versus other states. The new
30+
`.mean_time_in_state` metric can be used to track the absolute time spent in a
31+
state, even across heartbeats, so its value can be used as an absolute number.
32+
33+
### :chart_with_upwards_trend: Improvements
34+
35+
- Returned a `Session` object when `startSession` is called to improve the API
36+
usability.
37+
- Removed `SYSTEM_BOOT` from the default list of 'other' collected DropBox
38+
Entries. After some field testing, this DropBox Entry was not consistently
39+
collected and did not contain useful information.
40+
- Silenced tags in continuous logs that did not match the filter spec.
41+
42+
### :construction: Fixes
43+
44+
- Fixed a logs-to-metrics bug where it could not parse logcat tags with spaces.
45+
- Fixed a harmless SELinux violation where memfault_structured_app could not
46+
access its own data directory.
47+
- Fixed a bug in bort_cli.py's validation-sdk-integration command where it
48+
wouldn't check the right location for system_ext sepolicy.
49+
- Fixed a continuous log bug where spaces in the tag would break parsing.
50+
51+
### :house: Internal
52+
53+
- Migrated off junit5/jupiter back to junit4, at least until it has first party
54+
support from the Android team/
55+
- Added minio to the debug network security config for local development.
256

357
## v5.2.0 - November 15, 2024
458

MemfaultDumpster/ContinuousLogcat.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,11 @@ void ContinuousLogcat::rebuild_log_format(const std::vector<std::string>& filter
156156
// add filters
157157
for (auto &filter : filter_specs) {
158158
ALOGT("clog: filter: %s", filter.c_str());
159-
android_log_addFilterString(log_format.get(), filter.c_str());
159+
android_log_addFilterRule(log_format.get(), filter.c_str());
160160
}
161+
162+
// silence all other tags and levels
163+
android_log_addFilterRule(log_format.get(), "*:S");
161164
}
162165

163166
void ContinuousLogcat::join() {
@@ -281,7 +284,9 @@ void ContinuousLogcat::run() {
281284
// Force-checked if line should be printed, in some android
282285
// versions, the filters are not passed to the logd backend
283286
// so we need to recheck them
284-
if (!android_log_shouldPrintLine(log_format.get(), entry.tag, entry.priority)) {
287+
if (!android_log_shouldPrintLine(log_format.get(),
288+
std::string(entry.tag, entry.tagLen).c_str(),
289+
entry.priority)) {
285290
continue;
286291
}
287292

MemfaultPackages/bort-ota-lib/src/test/java/com/memfault/bort/ota/lib/ABUpdateActionHandlerTest.kt

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

33
import android.app.Application
44
import android.content.SharedPreferences
5+
import assertk.assertThat
6+
import assertk.assertions.containsExactly
7+
import assertk.assertions.isEmpty
8+
import assertk.assertions.isEqualTo
59
import com.memfault.bort.shared.SoftwareUpdateSettings
610
import io.mockk.coEvery
711
import io.mockk.every
@@ -11,9 +15,8 @@ import kotlinx.coroutines.delay
1115
import kotlinx.coroutines.runBlocking
1216
import kotlinx.coroutines.test.UnconfinedTestDispatcher
1317
import kotlinx.coroutines.test.runTest
14-
import org.junit.jupiter.api.Assertions.assertEquals
15-
import org.junit.jupiter.api.BeforeEach
16-
import org.junit.jupiter.api.Test
18+
import org.junit.Before
19+
import org.junit.Test
1720

1821
private const val OLD_SOFTWARE_VERSION = "old"
1922

@@ -51,7 +54,7 @@ class ABUpdateActionHandlerTest {
5154
isForced = null,
5255
)
5356

54-
@BeforeEach
57+
@Before
5558
fun setup() {
5659
softwareUpdateCheckerMock = mockk {
5760
coEvery { getLatestRelease() } coAnswers { ota }
@@ -108,61 +111,58 @@ class ABUpdateActionHandlerTest {
108111

109112
@Test
110113
fun testCallbacks() = runBlocking {
111-
assertEquals(1, updateEngineCallbacks.size)
114+
assertThat(updateEngineCallbacks.size).isEqualTo(1)
112115
}
113116

114117
@Test
115118
fun testCheckForUpdate_foreground() = runBlocking {
116119
handler.handle(State.Idle, Action.CheckForUpdate(background = false))
117-
assertEquals(
120+
assertThat(collectedStates).isEqualTo(
118121
listOf(State.CheckingForUpdates, State.UpdateAvailable(ota!!, showNotification = false)),
119-
collectedStates,
122+
120123
)
121-
assertEquals(listOf<Event>(), collectedEvents)
124+
assertThat(collectedEvents).isEmpty()
122125
}
123126

124127
@Test
125128
fun testCheckForUpdate_forcedNotSet() = runTest {
126129
ota = ota?.copy(isForced = null)
127130
handler.handle(State.Idle, Action.CheckForUpdate(background = true))
128-
assertEquals(
131+
assertThat(collectedStates).isEqualTo(
129132
listOf(State.CheckingForUpdates, State.UpdateAvailable(ota!!, showNotification = true)),
130-
collectedStates,
131133
)
132-
assertEquals(listOf<Event>(), collectedEvents)
134+
assertThat(collectedEvents).isEmpty()
133135
verify(exactly = 0) { scheduleDownload.scheduleDownload(any()) }
134136
}
135137

136138
@Test
137139
fun testCheckForUpdate_notForced() = runTest {
138140
ota = ota?.copy(isForced = false)
139141
handler.handle(State.Idle, Action.CheckForUpdate(background = true))
140-
assertEquals(
142+
assertThat(collectedStates).isEqualTo(
141143
listOf(State.CheckingForUpdates, State.UpdateAvailable(ota!!, showNotification = true)),
142-
collectedStates,
143144
)
144-
assertEquals(listOf<Event>(), collectedEvents)
145+
assertThat(collectedEvents).isEmpty()
145146
verify(exactly = 0) { scheduleDownload.scheduleDownload(any()) }
146147
}
147148

148149
@Test
149150
fun testCheckForUpdate_forced_scheduleAutoDownload() = runTest {
150151
ota = ota?.copy(isForced = true)
151152
handler.handle(State.Idle, Action.CheckForUpdate(background = true))
152-
assertEquals(
153+
assertThat(collectedStates).isEqualTo(
153154
listOf(State.CheckingForUpdates, State.UpdateAvailable(ota!!, showNotification = false)),
154-
collectedStates,
155155
)
156-
assertEquals(listOf<Event>(), collectedEvents)
156+
assertThat(collectedEvents).isEmpty()
157157
verify(exactly = 1) { scheduleDownload.scheduleDownload(ota!!) }
158158
}
159159

160160
@Test
161161
fun testCheckForUpdateAlreadyAtLatest() = runBlocking {
162162
ota = null
163163
handler.handle(State.Idle, Action.CheckForUpdate())
164-
assertEquals(listOf(State.CheckingForUpdates, State.Idle), collectedStates)
165-
assertEquals(listOf<Event>(Event.NoUpdatesAvailable), collectedEvents)
164+
assertThat(collectedStates).containsExactly(State.CheckingForUpdates, State.Idle)
165+
assertThat(collectedEvents).containsExactly(Event.NoUpdatesAvailable)
166166
}
167167

168168
@Test
@@ -173,8 +173,8 @@ class ABUpdateActionHandlerTest {
173173
onStatusUpdate(UPDATE_ENGINE_STATUS_DOWNLOADING, 0f)
174174
}
175175

176-
assertEquals(listOf(State.UpdateDownloading(ota!!)), collectedStates)
177-
assertEquals(listOf<Event>(), collectedEvents)
176+
assertThat(collectedStates).containsExactly(State.UpdateDownloading(ota!!))
177+
assertThat(collectedEvents).isEmpty()
178178
verify(exactly = 1) {
179179
testingUpdateEngine.applyPayload(
180180
ota!!.url,
@@ -195,14 +195,13 @@ class ABUpdateActionHandlerTest {
195195
onStatusUpdate(UPDATE_ENGINE_STATUS_DOWNLOADING, 1f)
196196
}
197197

198-
assertEquals(
198+
assertThat(collectedStates).isEqualTo(
199199
listOf(
200200
State.UpdateDownloading(ota!!, progress = 50),
201201
State.UpdateDownloading(ota!!, progress = 100),
202202
),
203-
collectedStates,
204203
)
205-
assertEquals(listOf<Event>(), collectedEvents)
204+
assertThat(collectedEvents).isEmpty()
206205
verify(exactly = 1) {
207206
testingUpdateEngine.applyPayload(
208207
ota!!.url,
@@ -216,13 +215,12 @@ class ABUpdateActionHandlerTest {
216215
@Test
217216
fun testRebootAfterCompletion() = runBlocking {
218217
handler.handle(State.RebootNeeded(ota!!), Action.Reboot)
219-
assertEquals(
218+
assertThat(collectedStates).isEqualTo(
220219
listOf<State>(
221220
State.RebootedForInstallation(ota!!, OLD_SOFTWARE_VERSION),
222221
),
223-
collectedStates,
224222
)
225-
assertEquals(listOf<Event>(), collectedEvents)
223+
assertThat(collectedEvents).isEmpty()
226224

227225
verify(exactly = 1) { rebootDevice() }
228226
}
@@ -236,55 +234,51 @@ class ABUpdateActionHandlerTest {
236234
onStatusUpdate(UPDATE_ENGINE_FINALIZING, 1f)
237235
}
238236

239-
assertEquals(
237+
assertThat(collectedStates).isEqualTo(
240238
listOf(
241239
State.Finalizing(ota!!, progress = 50),
242240
State.Finalizing(ota!!, progress = 100),
243241
),
244-
collectedStates,
245242
)
246-
assertEquals(listOf<Event>(), collectedEvents)
243+
assertThat(collectedEvents).isEmpty()
247244
}
248245

249246
@Test
250247
fun testBecomeIdle() = runBlocking {
251248
forEachCallback {
252249
onStatusUpdate(UPDATE_ENGINE_STATUS_IDLE, 0f)
253250
}
254-
assertEquals(
251+
assertThat(collectedStates).isEqualTo(
255252
listOf(
256253
State.Idle,
257254
),
258-
collectedStates,
259255
)
260-
assertEquals(listOf<Event>(), collectedEvents)
256+
assertThat(collectedEvents).isEmpty()
261257
}
262258

263259
@Test
264260
fun testUpdateFinishedNeedReboot() = runBlocking {
265261
forEachCallback {
266262
onStatusUpdate(UPDATE_ENGINE_UPDATED_NEED_REBOOT, 0f)
267263
}
268-
assertEquals(
264+
assertThat(collectedStates).isEqualTo(
269265
listOf(
270266
State.RebootNeeded(ota!!),
271267
),
272-
collectedStates,
273268
)
274-
assertEquals(listOf<Event>(), collectedEvents)
269+
assertThat(collectedEvents).isEmpty()
275270
}
276271

277272
@Test
278273
fun testDownloadFailedTrigger() = runBlocking {
279274
forEachCallback {
280275
onPayloadApplicationComplete(UPDATE_ENGINE_ERROR_DOWNLOAD_TRANSFER_ERROR)
281276
}
282-
assertEquals(listOf<State>(), collectedStates)
283-
assertEquals(
277+
assertThat(collectedStates).isEmpty()
278+
assertThat(collectedEvents).isEqualTo(
284279
listOf<Event>(
285280
Event.DownloadFailed,
286281
),
287-
collectedEvents,
288282
)
289283
}
290284

@@ -293,12 +287,11 @@ class ABUpdateActionHandlerTest {
293287
forEachCallback {
294288
onPayloadApplicationComplete(-1)
295289
}
296-
assertEquals(listOf<State>(), collectedStates)
297-
assertEquals(
290+
assertThat(collectedStates).isEmpty()
291+
assertThat(collectedEvents).isEqualTo(
298292
listOf<Event>(
299293
Event.VerificationFailed,
300294
),
301-
collectedEvents,
302295
)
303296
}
304297

MemfaultPackages/bort-ota-lib/src/test/java/com/memfault/bort/ota/lib/BortSoftwareUpdateSettingsProviderTest.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import android.database.MatrixCursor
55
import android.net.Uri
66
import androidx.work.NetworkType.CONNECTED
77
import androidx.work.NetworkType.UNMETERED
8+
import assertk.assertThat
9+
import assertk.assertions.isEqualTo
10+
import assertk.assertions.isNull
811
import com.memfault.bort.shared.LegacySoftwareUpdateSettings
912
import com.memfault.bort.shared.SoftwareUpdateSettings
1013
import com.memfault.bort.shared.SoftwareUpdateSettings.Companion.createCursor
@@ -13,8 +16,6 @@ import io.mockk.every
1316
import io.mockk.mockk
1417
import kotlinx.serialization.SerializationException
1518
import kotlinx.serialization.json.Json
16-
import org.junit.Assert.assertEquals
17-
import org.junit.Assert.assertNull
1819
import org.junit.Test
1920
import org.junit.runner.RunWith
2021
import org.robolectric.RobolectricTestRunner
@@ -46,30 +47,30 @@ class BortSoftwareUpdateSettingsProviderTest {
4647
fun oldOtaNewBort() {
4748
cursor = createCursor(settings)
4849
val provider = LegacyProviderClient(resolver)
49-
assertEquals(settings.asLegacyOtaSettings(), provider.settings())
50+
assertThat(provider.settings()).isEqualTo(settings.asLegacyOtaSettings())
5051
}
5152

5253
@Test
5354
fun oldOtaNewBort_newFormat_crashes() {
5455
// This is what would have happened if we did not go to all this trouble to include "legacy" formatted settings.
5556
cursor = legacyCreateCursorWithNewFormat(settings)
5657
val provider = LegacyProviderClient(resolver)
57-
assertNull(provider.settings())
58+
assertThat(provider.settings()).isNull()
5859
}
5960

6061
@Test
6162
fun newOtaNewBort() {
6263
cursor = createCursor(settings)
6364
val provider = BortSoftwareUpdateSettingsFetcher(resolver)
64-
assertEquals(settings, provider.settings())
65+
assertThat(provider.settings()).isEqualTo(settings)
6566
}
6667

6768
@Test
6869
fun newOtaOldBort() {
6970
cursor = legacyCreateCursor(settings.asLegacyOtaSettings())
7071
val provider = BortSoftwareUpdateSettingsFetcher(resolver)
7172
// Default value should be used for new field.
72-
assertEquals(settings.copy(downloadNetworkTypeConstraint = UNMETERED), provider.settings())
73+
assertThat(provider.settings()).isEqualTo(settings.copy(downloadNetworkTypeConstraint = UNMETERED))
7374
}
7475

7576
/**

0 commit comments

Comments
 (0)