Put metadata or stats into each dropbox incident report.
Bug: 65451198
Test: atest incidentd_test
Change-Id: Ib406b177ad7f1b4bda7fef2e606fc66a9836e060
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 3f0e331..c5078f0 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -73,11 +73,6 @@
case android::os::DEST_LOCAL:
return PrivacySpec(dest);
default:
- return PrivacySpec();
+ return PrivacySpec(android::os::DEST_AUTOMATIC);
}
}
-
-PrivacySpec PrivacySpec::get_default_dropbox_spec()
-{
- return PrivacySpec(android::os::DEST_AUTOMATIC);
-}
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index 4f3db67..ce1b8e9 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -75,7 +75,6 @@
// Constructs spec using static methods below.
static PrivacySpec new_spec(int dest);
- static PrivacySpec get_default_dropbox_spec();
private:
PrivacySpec(uint8_t dest) : dest(dest) {}
};
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index b9f479b..06baeba 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -18,6 +18,7 @@
#include "Reporter.h"
+#include "Privacy.h"
#include "report_directory.h"
#include "section_list.h"
@@ -65,7 +66,9 @@
:mRequests(),
mSections(),
mMainFd(-1),
- mMainDest(-1)
+ mMainDest(-1),
+ mMetadata(),
+ mSectionStats()
{
}
@@ -79,18 +82,32 @@
{
mRequests.push_back(request);
mSections.merge(request->args);
+ mMetadata.set_request_size(mMetadata.request_size() + 1);
}
void
ReportRequestSet::setMainFd(int fd)
{
mMainFd = fd;
+ mMetadata.set_use_dropbox(fd > 0);
}
void
ReportRequestSet::setMainDest(int dest)
{
mMainDest = dest;
+ PrivacySpec spec = PrivacySpec::new_spec(dest);
+ switch (spec.dest) {
+ case android::os::DEST_AUTOMATIC:
+ mMetadata.set_dest(IncidentMetadata_Destination_AUTOMATIC);
+ break;
+ case android::os::DEST_EXPLICIT:
+ mMetadata.set_dest(IncidentMetadata_Destination_EXPLICIT);
+ break;
+ case android::os::DEST_LOCAL:
+ mMetadata.set_dest(IncidentMetadata_Destination_LOCAL);
+ break;
+ }
}
bool
@@ -98,6 +115,16 @@
return mSections.containsSection(id);
}
+IncidentMetadata::SectionStats*
+ReportRequestSet::sectionStats(int id) {
+ if (mSectionStats.find(id) == mSectionStats.end()) {
+ auto stats = mMetadata.add_sections();
+ stats->set_id(id);
+ mSectionStats[id] = stats;
+ }
+ return mSectionStats[id];
+}
+
// ================================================================================
Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
@@ -128,12 +155,12 @@
Reporter::run_report_status_t
Reporter::runReport()
{
-
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
int mainDest = -1;
HeaderSection headers;
+ MetadataSection metadataSection;
// See if we need the main file
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
@@ -182,7 +209,7 @@
const int id = (*section)->id;
if (this->batch.containsSection(id)) {
ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
- // Notify listener of starting
+ // Notify listener of starting.
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
(*it)->listener->onReportSectionStatus(id,
@@ -191,14 +218,20 @@
}
// Execute - go get the data and write it into the file descriptors.
+ auto stats = batch.sectionStats(id);
+ int64_t startTime = uptimeMillis();
err = (*section)->Execute(&batch);
+ int64_t endTime = uptimeMillis();
+
+ stats->set_success(err == NO_ERROR);
+ stats->set_exec_duration_ms(endTime - startTime);
if (err != NO_ERROR) {
ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
(*section)->name.string(), id, strerror(-err));
goto DONE;
}
- // Notify listener of starting
+ // Notify listener of ending.
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
(*it)->listener->onReportSectionStatus(id,
@@ -210,6 +243,9 @@
}
DONE:
+ // Reports the metdadata when taking the incident report.
+ if (!isTest) metadataSection.Execute(&batch);
+
// Close the file.
if (mainFd >= 0) {
close(mainFd);
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index f30ecf0..6058068 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -17,9 +17,12 @@
#ifndef REPORTER_H
#define REPORTER_H
+#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
+
#include <android/os/IIncidentReportStatusListener.h>
#include <android/os/IncidentReportArgs.h>
+#include <map>
#include <string>
#include <vector>
@@ -61,13 +64,20 @@
iterator end() { return mRequests.end(); }
int mainFd() { return mMainFd; }
- bool containsSection(int id);
int mainDest() { return mMainDest; }
+ IncidentMetadata& metadata() { return mMetadata; }
+
+ bool containsSection(int id);
+ IncidentMetadata::SectionStats* sectionStats(int id);
+
private:
vector<sp<ReportRequest>> mRequests;
IncidentReportArgs mSections;
int mMainFd;
int mMainDest;
+
+ IncidentMetadata mMetadata;
+ map<int, IncidentMetadata::SectionStats*> mSectionStats;
};
// ================================================================================
@@ -81,8 +91,8 @@
ReportRequestSet batch;
- Reporter();
- Reporter(const char* directory);
+ Reporter(); // PROD must use this constructor.
+ Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index faeab87..3c76298 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -45,6 +45,7 @@
// special section ids
const int FIELD_ID_INCIDENT_HEADER = 1;
+const int FIELD_ID_INCIDENT_METADATA = 2;
// incident section parameters
const int WAIT_MAX = 5;
@@ -149,6 +150,12 @@
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
+ auto stats = requests->sectionStats(id);
+
+ stats->set_dump_size_bytes(data.size());
+ stats->set_dump_duration_ms(buffer.durationMs());
+ stats->set_timed_out(buffer.timedOut());
+ stats->set_is_truncated(buffer.truncated());
// The streaming ones, group requests by spec in order to save unnecessary strip operations
map<PrivacySpec, vector<sp<ReportRequest>>> requestsBySpec;
@@ -182,9 +189,7 @@
// The dropbox file
if (requests->mainFd() >= 0) {
- PrivacySpec spec = requests->mainDest() < 0 ?
- PrivacySpec::get_default_dropbox_spec() :
- PrivacySpec::new_spec(requests->mainDest());
+ PrivacySpec spec = PrivacySpec::new_spec(requests->mainDest());
err = privacyBuffer.strip(spec);
if (err != NO_ERROR) return err; // the buffer data is corrupted.
if (privacyBuffer.size() == 0) goto DONE;
@@ -196,6 +201,7 @@
writeable++;
ALOGD("Section %d flushed %zu bytes to dropbox %d with spec %d", id,
privacyBuffer.size(), requests->mainFd(), spec.dest);
+ stats->set_report_size_bytes(privacyBuffer.size());
}
DONE:
@@ -236,7 +242,7 @@
// So the idea is only requests with negative fd are written to dropbox file.
int fd = request->fd >= 0 ? request->fd : requests->mainFd();
- write_section_header(fd, FIELD_ID_INCIDENT_HEADER, buf->size());
+ write_section_header(fd, id, buf->size());
write_all(fd, (uint8_t const*)buf->data(), buf->size());
// If there was an error now, there will be an error later and we will remove
// it from the list then.
@@ -244,7 +250,35 @@
}
return NO_ERROR;
}
+// ================================================================================
+MetadataSection::MetadataSection()
+ :Section(FIELD_ID_INCIDENT_METADATA, 0)
+{
+}
+MetadataSection::~MetadataSection()
+{
+}
+
+status_t
+MetadataSection::Execute(ReportRequestSet* requests) const
+{
+ std::string metadataBuf;
+ requests->metadata().SerializeToString(&metadataBuf);
+ for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+ const sp<ReportRequest> request = *it;
+ if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
+ continue;
+ }
+ write_section_header(request->fd, id, metadataBuf.size());
+ write_all(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ }
+ if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
+ write_section_header(requests->mainFd(), id, metadataBuf.size());
+ write_all(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ }
+ return NO_ERROR;
+}
// ================================================================================
FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
:Section(id, timeoutMs),
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index d440ee9..80cc033 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -59,6 +59,18 @@
};
/**
+ * Section that generates incident metadata.
+ */
+class MetadataSection : public Section
+{
+public:
+ MetadataSection();
+ virtual ~MetadataSection();
+
+ virtual status_t Execute(ReportRequestSet* requests) const;
+};
+
+/**
* Section that reads in a file.
*/
class FileSection : public Section