Android Bug Reports
The Memfault SDK can trigger the collection and upload of Android bugreports from the device, where they are available for download in the future.
/system/bin/MemfaultDumpstateRunner
The Bort app sends a request to the MemfaultDumpstateRunner
to capture the
bug report.
This native program is exposed as an "init.rc service" (see memfault_init.rc
for details). This is so that it can be executed in the required dumpstate
security context, but get triggered by the Bort app, via the UsageReporter
system app. The Bort app runs in the much less capable security context compared
to MemfaultDumpstateRunner
.
- trigger
/system/bin/dumpstate
(through another init.rc service,memfault_dumpstatez
), - copy the bugreport.zip file out of the shell file system sandbox and into Bort's file system sandbox,
- broadcast an Intent with the final path such that the Android SDK can process it further.
To permit MemfaultDumpstateRunner
to do all the things it needs to do, it is
labelled with the existing/builtin dumpstate
sepolicy label and is broadened a
little further as well (see memfault_dumpstate_runner.te
). It's possible to
make a tail-made policy that is narrower in scope but this requires more changes
to the builtin AOSP system/sepolicy, so we choose to piggy-back on the existing
dumpstate
type instead. This is also the approach that the AOSP Car product
(Android Auto) takes. See sepolicy/file_contexts
for reference.
/system/bin/dumpstate
This is the AOSP-built-in Bug Report capturing program; it requires no modification.
The Android SDK provides an optional patch so dumpstate can run in its default behavior, but also in a "minimal" mode. See Minimal Mode below for more information.
Note that it is not triggered through the builtin dumpstatez
init.rc service,
but through the slightly specialized memfault_dumpstatez
. See
memfault_init.rc
for details on the differences.
Bug report capture period
The Android SDK can periodically generate bug reports by scheduling a periodic
task to trigger the MemfaultDumpstateRunner
.
The SDK registers a handler (broadcast receiver) for the system boot event as well as when the app itself is updated or installed. When either of these happens, the app will register the periodic task if one is not registered.
There are configuration options to set the period of this task as well as the initial delay for when the first bug report is generated (e.g. if you wish to wait until more data is available). See SDK settings.
Bug reports can also be triggered programmatically via an Intent
.
"Minimal mode" bug report capture
Memfault provides the option to capture "minimal" bug reports. These collect the data required for Memfault diagnostics while being roughly 5x smaller and requiring 10x less load on the system. If system load or bandwidth are concerns for your deployment, we recommend using minimal mode.
If you do not have those constraints and would like to download the bug reports from Memfault to look at deeper diagnostics information, we recommend disabling minimal mode and capturing "full" bug reports.
Enable "minimal" mode via the SDK settings.
Triggering a bug report programmatically
In addition to generating bug reports at regular intervals, you may also wish to capture a bug report if a significant event occurs. Doing this will not affect the scheduled bug reports.
Note that if the dumpstate runner is busy capturing a bug report already, the in-flight bug report will continue and the interrupting request will be ignored.
Triggering a bug report requires that the sender hold the permission specified
in the BORT_CONTROL_PERMISSION
property in bort.properties
. The default is
the com.memfault.bort.permission.CONTROL
.
An optional ID can be provided via the string extra
com.memfault.intent.extra.BUG_REPORT_REQUEST_ID
. When provided, the
dumpstate.memfault.requestid
system property is set to this value. The value
can be any string of up to 40 ASCII characters.
Intent("com.memfault.intent.action.REQUEST_BUG_REPORT").apply {
component = ComponentName(
APPLICATION_ID_BORT,
"com.memfault.bort.receivers.ControlReceiver"
)
// Optionally provide a request ID:
putExtra("com.memfault.intent.extra.BUG_REPORT_REQUEST_ID", UUID.randomUUID().toString())
// Optionally enable minimal mode:
putExtra("com.memfault.intent.extra.BUG_REPORT_MINIMAL_MODE_BOOL", true)
// Optionally provide a BroadcastReceiver for status replies:
putExtra("com.memfault.intent.extra.BUG_REPORT_REQUEST_REPLY_RECEIVER",
"com.acme.app/com.acme.app.BortBugReportRequestReplyReceiver")
}.also {
context.sendBroadcast(it)
}
Receiving bug report request status replies
Optionally, a BroadcastReceiver
can be implemented to handle the status reply
that the Android SDK sends in response to a bug report request. Replies are sent
using targeted Intent broadcasts. They are only sent when the
com.memfault.intent.extra.BUG_REPORT_REQUEST_REPLY_RECEIVER
extra is set to
the com.package.id/qualified.class.name
of the BroadcastReceiver
(see
example above).
To register a receiver class called BortBugReportRequestReplyReceiver
, add
this to your AndroidManifest.xml
:
<receiver
android:name=".BortBugReportRequestReplyReceiver"
android:permission="android.permission.DUMP">
<intent-filter>
<action android:name="com.memfault.intent.action.BUG_REPORT_REQUEST_REPLY" />
</intent-filter>
</receiver>
The code to handle the reply Intent would look like something along these lines:
class BortBugReportRequestReplyReceiver : BroadcastReceiver() {
fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action != "com.memfault.intent.action.BUG_REPORT_REQUEST_REPLY") return
// status can be "OK_UPLOAD_COMPLETED", "ERROR_ALREADY_PENDING", "ERROR_TIMEOUT",
// "ERROR_SDK_NOT_ENABLED" or "ERROR_RATE_LIMITED":
val status = intent.getStringExtra("com.memfault.intent.extra.BUG_REPORT_REQUEST_STATUS")
// The request ID that was originally provided:
val requestId = intent.getStringExtra("com.memfault.intent.extra.BUG_REPORT_REQUEST_ID")
Log.i("Got reply for bug report request with ID: $requestId status: $status")
}
}
Triggering a bug report with bort_cli.py
If you wish to generate a bug report using the SDK on a development device over
ADB, bort_cli.py
provides a convenience command:
./bort_cli.py request-bug-report --bort-app-id your.app.id