incidentd can now handle multiple callers asking it for incident reports
Test: bit incident_test:* GtsIncidentManagerTestCases:*
Bug: 123543706
Change-Id: I9f671dd5d8b2ad139f952a23e575c2be16120459
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 2a3abd7..e7a474f 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -15,103 +15,247 @@
*/
#pragma once
-#ifndef REPORTER_H
-#define REPORTER_H
+#include "FdBuffer.h"
+#include "Throttler.h"
+#include "WorkDirectory.h"
+#include "frameworks/base/core/proto/android/os/metadata.pb.h"
+#include <android/content/ComponentName.h>
#include <android/os/IIncidentReportStatusListener.h>
#include <android/os/IncidentReportArgs.h>
+#include <android/util/protobuf.h>
#include <map>
#include <string>
#include <vector>
#include <time.h>
-
-#include "Throttler.h"
-#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
+#include <stdarg.h>
namespace android {
namespace os {
namespace incidentd {
+using namespace std;
+using namespace android::content;
+using namespace android::os;
+
+class Section;
+
// ================================================================================
-struct ReportRequest : public virtual RefBase {
+class ReportRequest : public virtual RefBase {
+public:
IncidentReportArgs args;
- sp<IIncidentReportStatusListener> listener;
- int fd;
- status_t err;
ReportRequest(const IncidentReportArgs& args, const sp<IIncidentReportStatusListener>& listener,
int fd);
virtual ~ReportRequest();
+ bool isStreaming() { return mIsStreaming; }
+
+ void setStatus(status_t err) { mStatus = err; }
+ status_t getStatus() const { return mStatus; }
+
bool ok(); // returns true if the request is ok for write.
+
+ bool containsSection(int sectionId) const { return args.containsSection(sectionId); }
+
+ sp<IIncidentReportStatusListener> getListener() { return mListener; }
+
+ int getFd() { return mFd; }
+
+ int setPersistedFd(int fd);
+
+ void closeFd();
+
+private:
+ sp<IIncidentReportStatusListener> mListener;
+ int mFd;
+ bool mIsStreaming;
+ status_t mStatus;
};
// ================================================================================
-class ReportRequestSet {
+class ReportBatch : public virtual RefBase {
public:
- ReportRequestSet();
- ~ReportRequestSet();
+ ReportBatch();
+ virtual ~ReportBatch();
- void add(const sp<ReportRequest>& request);
- void setMainFd(int fd);
- void setMainDest(int dest);
+ // TODO: Should there be some kind of listener associated with the
+ // component? Could be good for getting status updates e.g. in the ui,
+ // as it progresses. But that's out of scope for now.
- typedef vector<sp<ReportRequest>>::iterator iterator;
+ /**
+ * Schedule a report for the "main" report, where it will be delivered to
+ * the uploaders and/or dropbox.
+ */
+ void addPersistedReport(const IncidentReportArgs& args);
- iterator begin() { return mRequests.begin(); }
- iterator end() { return mRequests.end(); }
+ /**
+ * Adds a ReportRequest to the queue for one that has a listener an and fd
+ */
+ void addStreamingReport(const IncidentReportArgs& args,
+ const sp<IIncidentReportStatusListener>& listener, int streamFd);
- int mainFd() { return mMainFd; }
- int mainDest() { return mMainDest; }
- IncidentMetadata& metadata() { return mMetadata; }
- map<int, IncidentMetadata::SectionStats>& allSectionStats() { return mSectionStats; }
+ /**
+ * Returns whether both queues are empty.
+ */
+ bool empty() const;
+ /**
+ * Returns whether there are any persisted records.
+ */
+ bool hasPersistedReports() const { return mPersistedRequests.size() > 0; }
+
+ /**
+ * Return the persisted request for the given component, or nullptr.
+ */
+ sp<ReportRequest> getPersistedRequest(const ComponentName& component);
+
+ /**
+ * Call func(request) for each Request.
+ */
+ void forEachPersistedRequest(const function<void (const sp<ReportRequest>&)>& func);
+
+ /**
+ * Call func(request) for each Request.
+ */
+ void forEachStreamingRequest(const function<void (const sp<ReportRequest>&)>& func);
+
+ /**
+ * Call func(request) for each file descriptor that has
+ */
+ void forEachFd(int sectionId, const function<void (const sp<ReportRequest>&)>& func);
+
+ /**
+ * Call func(listener) for every listener in this batch.
+ */
+ void forEachListener(const function<void (const sp<IIncidentReportStatusListener>&)>& func);
+
+ /**
+ * Call func(listener) for every listener in this batch that requests
+ * sectionId.
+ */
+ void forEachListener(int sectionId,
+ const function<void (const sp<IIncidentReportStatusListener>&)>& func);
+ /**
+ * Get an IncidentReportArgs that represents the combined args for the
+ * persisted requests.
+ */
+ void getCombinedPersistedArgs(IncidentReportArgs* results);
+
+ /**
+ * Return whether any of the requests contain the section.
+ */
bool containsSection(int id);
- IncidentMetadata::SectionStats* sectionStats(int id);
+
+ /**
+ * Remove all of the broadcast (persisted) requests.
+ */
+ void clearPersistedRequests();
+
+ /**
+ * Get the requests that have encountered errors.
+ */
+ void getFailedRequests(vector<sp<ReportRequest>>* requests);
+
+ /**
+ * Remove the request from whichever list it's in.
+ */
+ void removeRequest(const sp<ReportRequest>& request);
+
private:
- vector<sp<ReportRequest>> mRequests;
- IncidentReportArgs mSections;
- int mMainFd;
- int mMainDest;
+ map<ComponentName, sp<ReportRequest>> mPersistedRequests;
+ vector<sp<ReportRequest>> mStreamingRequests;
+};
- IncidentMetadata mMetadata;
- map<int, IncidentMetadata::SectionStats> mSectionStats;
+// ================================================================================
+class ReportWriter {
+public:
+ ReportWriter(const sp<ReportBatch>& batch);
+ ~ReportWriter();
+
+ void setPersistedFile(sp<ReportFile> file);
+ void setMaxPersistedPrivacyPolicy(uint8_t privacyPolicy);
+
+ void startSection(int sectionId);
+ void endSection(IncidentMetadata::SectionStats* sectionStats);
+
+ void setSectionStats(const FdBuffer& buffer);
+
+ void warning(const Section* section, status_t err, const char* format, ...);
+ void error(const Section* section, status_t err, const char* format, ...);
+
+ status_t writeSection(const FdBuffer& buffer);
+
+private:
+ // Data about all requests
+ sp<ReportBatch> mBatch;
+
+ /**
+ * The file on disk where we will store the persisted file.
+ */
+ sp<ReportFile> mPersistedFile;
+
+ /**
+ * The least restricted privacy policy of all of the perstited
+ * requests. We pre-filter to that to save disk space.
+ */
+ uint8_t mMaxPersistedPrivacyPolicy;
+
+ /**
+ * The current section that is being written.
+ */
+ int mCurrentSectionId;
+
+ /**
+ * The time that that the current section was started.
+ */
+ int64_t mSectionStartTimeMs;
+
+ /**
+ * The last section that setSectionStats was called for, so if someone misses
+ * it we can log that.
+ */
+ int mSectionStatsCalledForSectionId;
+
+ /*
+ * Fields for IncidentMetadata.SectionStats. Set by setSectionStats. Accessed by
+ * getSectionStats.
+ */
+ int32_t mDumpSizeBytes;
+ int64_t mDumpDurationMs;
+ bool mSectionTimedOut;
+ bool mSectionTruncated;
+ bool mSectionBufferSuccess;
+ bool mHadError;
+ string mSectionErrors;
+ size_t mMaxSectionDataFilteredSize;
+
+ void vflog(const Section* section, status_t err, int level, const char* levelText,
+ const char* format, va_list args);
};
// ================================================================================
class Reporter : public virtual RefBase {
public:
- enum run_report_status_t { REPORT_FINISHED = 0, REPORT_NEEDS_DROPBOX = 1 };
+ Reporter(const sp<WorkDirectory>& workDirectory, const sp<ReportBatch>& batch);
- ReportRequestSet batch;
-
- Reporter(); // PROD must use this constructor.
- explicit Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
- run_report_status_t runReport(size_t* reportByteSize);
-
- static run_report_status_t upload_backlog();
+ void runReport(size_t* reportByteSize);
private:
- String8 mIncidentDirectory;
+ sp<WorkDirectory> mWorkDirectory;
+ ReportWriter mWriter;
+ sp<ReportBatch> mBatch;
+ sp<ReportFile> mPersistedFile;
- string mFilename;
- off_t mMaxSize;
- size_t mMaxCount;
- time_t mStartTime;
-
- status_t create_file(int* fd);
-
- bool isTest = true; // default to true for testing
+ void cancel_and_remove_failed_requests();
};
} // namespace incidentd
} // namespace os
} // namespace android
-
-#endif // REPORTER_H