summaryrefslogtreecommitdiff
path: root/cmds/incidentd/src/Reporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/incidentd/src/Reporter.cpp')
-rw-r--r--cmds/incidentd/src/Reporter.cpp149
1 files changed, 57 insertions, 92 deletions
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 1ecb291c84a1..34930aa57321 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -17,13 +17,12 @@
#define LOG_TAG "incidentd"
#include "Reporter.h"
-#include "protobuf.h"
#include "report_directory.h"
#include "section_list.h"
-#include <private/android_filesystem_config.h>
#include <android/os/DropBoxManager.h>
+#include <private/android_filesystem_config.h>
#include <utils/SystemClock.h>
#include <sys/types.h>
@@ -35,21 +34,7 @@
/**
* The directory where the incident reports are stored.
*/
-static const String8 INCIDENT_DIRECTORY("/data/incidents");
-
-static status_t
-write_all(int fd, uint8_t const* buf, size_t size)
-{
- while (size > 0) {
- ssize_t amt = ::write(fd, buf, size);
- if (amt < 0) {
- return -errno;
- }
- size -= amt;
- buf += amt;
- }
- return NO_ERROR;
-}
+static const char* INCIDENT_DIRECTORY = "/data/misc/incidents/";
// ================================================================================
ReportRequest::ReportRequest(const IncidentReportArgs& a,
@@ -63,12 +48,22 @@ ReportRequest::ReportRequest(const IncidentReportArgs& a,
ReportRequest::~ReportRequest()
{
+ if (fd >= 0) {
+ // clean up the opened file descriptor
+ close(fd);
+ }
+}
+
+bool
+ReportRequest::ok()
+{
+ return fd >= 0 && err == NO_ERROR;
}
// ================================================================================
ReportRequestSet::ReportRequestSet()
:mRequests(),
- mWritableCount(0),
+ mSections(),
mMainFd(-1)
{
}
@@ -77,56 +72,30 @@ ReportRequestSet::~ReportRequestSet()
{
}
+// TODO: dedup on exact same args and fd, report the status back to listener!
void
ReportRequestSet::add(const sp<ReportRequest>& request)
{
mRequests.push_back(request);
- mWritableCount++;
+ mSections.merge(request->args);
}
void
ReportRequestSet::setMainFd(int fd)
{
mMainFd = fd;
- mWritableCount++;
}
-status_t
-ReportRequestSet::write(uint8_t const* buf, size_t size)
-{
- status_t err = EBADF;
-
- // The streaming ones
- int const N = mRequests.size();
- for (int i=N-1; i>=0; i--) {
- sp<ReportRequest> request = mRequests[i];
- if (request->fd >= 0 && request->err == NO_ERROR) {
- err = write_all(request->fd, buf, size);
- if (err != NO_ERROR) {
- request->err = err;
- mWritableCount--;
- }
- }
- }
-
- // The dropbox file
- if (mMainFd >= 0) {
- err = write_all(mMainFd, buf, size);
- if (err != NO_ERROR) {
- mMainFd = -1;
- mWritableCount--;
- }
- }
-
- // Return an error only when there are no FDs to write.
- return mWritableCount > 0 ? NO_ERROR : err;
+bool
+ReportRequestSet::containsSection(int id) {
+ return mSections.containsSection(id);
}
-
// ================================================================================
-Reporter::Reporter()
- :args(),
- batch()
+Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
+
+Reporter::Reporter(const char* directory)
+ :batch()
{
char buf[100];
@@ -134,10 +103,15 @@ Reporter::Reporter()
mMaxSize = 100 * 1024 * 1024;
mMaxCount = 100;
+ // string ends up with '/' is a directory
+ String8 dir = String8(directory);
+ if (directory[dir.size() - 1] != '/') dir += "/";
+ mIncidentDirectory = dir.string();
+
// There can't be two at the same time because it's on one thread.
mStartTime = time(NULL);
- strftime(buf, sizeof(buf), "/incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
- mFilename = INCIDENT_DIRECTORY + buf;
+ strftime(buf, sizeof(buf), "incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
+ mFilename = mIncidentDirectory + buf;
}
Reporter::~Reporter()
@@ -151,6 +125,7 @@ Reporter::runReport()
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
+ HeaderSection headers;
// See if we need the main file
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
@@ -161,20 +136,20 @@ Reporter::runReport()
}
if (needMainFd) {
// Create the directory
- err = create_directory(INCIDENT_DIRECTORY);
+ if (!isTest) err = create_directory(mIncidentDirectory);
if (err != NO_ERROR) {
- goto done;
+ goto DONE;
}
// If there are too many files in the directory (for whatever reason),
// delete the oldest ones until it's under the limit. Doing this first
// does mean that we can go over, so the max size is not a hard limit.
- clean_directory(INCIDENT_DIRECTORY, mMaxSize, mMaxCount);
+ if (!isTest) clean_directory(mIncidentDirectory, mMaxSize, mMaxCount);
// Open the file.
err = create_file(&mainFd);
if (err != NO_ERROR) {
- goto done;
+ goto DONE;
}
// Add to the set
@@ -189,32 +164,14 @@ Reporter::runReport()
}
// Write the incident headers
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
- const sp<ReportRequest> request = (*it);
- const vector<vector<int8_t>>& headers = request->args.headers();
-
- for (vector<vector<int8_t>>::const_iterator buf=headers.begin(); buf!=headers.end();
- buf++) {
- int fd = request->fd >= 0 ? request->fd : mainFd;
-
- uint8_t buffer[20];
- uint8_t* p = write_length_delimited_tag_header(buffer, FIELD_ID_INCIDENT_HEADER,
- buf->size());
- write_all(fd, buffer, p-buffer);
-
- 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.
- }
- }
+ headers.Execute(&batch);
// For each of the report fields, see if we need it, and if so, execute the command
// and report to those that care that we're doing it.
for (const Section** section=SECTION_LIST; *section; section++) {
const int id = (*section)->id;
- ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
-
- if (this->args.containsSection(id)) {
+ if (this->batch.containsSection(id)) {
+ ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
// Notify listener of starting
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
@@ -226,9 +183,9 @@ Reporter::runReport()
// Execute - go get the data and write it into the file descriptors.
err = (*section)->Execute(&batch);
if (err != NO_ERROR) {
- ALOGW("Incident section %s (%d) failed. Stopping report.",
- (*section)->name.string(), id);
- goto done;
+ ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
+ (*section)->name.string(), id, strerror(-err));
+ goto DONE;
}
// Notify listener of starting
@@ -238,10 +195,11 @@ Reporter::runReport()
IIncidentReportStatusListener::STATUS_FINISHED);
}
}
+ ALOGD("Finish incident report section %d '%s'", id, (*section)->name.string());
}
}
-done:
+DONE:
// Close the file.
if (mainFd >= 0) {
close(mainFd);
@@ -270,7 +228,7 @@ done:
// If the status was ok, delete the file. If not, leave it around until the next
// boot or the next checkin. If the directory gets too big older files will
// be rotated out.
- unlink(mFilename.c_str());
+ if(!isTest) unlink(mFilename.c_str());
}
return REPORT_FINISHED;
@@ -284,7 +242,7 @@ Reporter::create_file(int* fd)
{
const char* filename = mFilename.c_str();
- *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0660);
+ *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
if (*fd < 0) {
ALOGE("Couldn't open incident file: %s (%s)", filename, strerror(errno));
return -errno;
@@ -303,28 +261,34 @@ Reporter::create_file(int* fd)
return NO_ERROR;
}
-// ================================================================================
Reporter::run_report_status_t
Reporter::upload_backlog()
{
DIR* dir;
struct dirent* entry;
struct stat st;
+ status_t err;
+
+ ALOGD("Start uploading backlogs in %s", INCIDENT_DIRECTORY);
+ if ((err = create_directory(INCIDENT_DIRECTORY)) != NO_ERROR) {
+ ALOGE("directory doesn't exist: %s", strerror(-err));
+ return REPORT_FINISHED;
+ }
- if ((dir = opendir(INCIDENT_DIRECTORY.string())) == NULL) {
- ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY.string());
+ if ((dir = opendir(INCIDENT_DIRECTORY)) == NULL) {
+ ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY);
return REPORT_NEEDS_DROPBOX;
}
- String8 dirbase(INCIDENT_DIRECTORY + "/");
sp<DropBoxManager> dropbox = new DropBoxManager();
// Enumerate, count and add up size
+ int count = 0;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] == '.') {
continue;
}
- String8 filename = dirbase + entry->d_name;
+ String8 filename = String8(INCIDENT_DIRECTORY) + entry->d_name;
if (stat(filename.string(), &st) != 0) {
ALOGE("Unable to stat file %s", filename.string());
continue;
@@ -343,8 +307,9 @@ Reporter::upload_backlog()
// boot or the next checkin. If the directory gets too big older files will
// be rotated out.
unlink(filename.string());
+ count++;
}
-
+ ALOGD("Successfully uploaded %d files to Dropbox.", count);
closedir(dir);
return REPORT_FINISHED;