blob: c0b53586a8ceb8440f4eed2b62ae4ccf36079362 [file] [log] [blame]
Joe Onorato1754d742016-11-21 17:51:35 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Yi Jinb592e3b2018-02-01 15:17:04 -080016#include "Log.h"
Joe Onorato1754d742016-11-21 17:51:35 -080017
18#include "Reporter.h"
Joe Onorato1754d742016-11-21 17:51:35 -080019
Yi Jin329130b2018-02-09 16:47:47 -080020#include "Privacy.h"
Joe Onorato1754d742016-11-21 17:51:35 -080021#include "report_directory.h"
22#include "section_list.h"
23
Joe Onorato1754d742016-11-21 17:51:35 -080024#include <android/os/DropBoxManager.h>
Yi Jin0a3406f2017-06-22 19:23:11 -070025#include <private/android_filesystem_config.h>
Joe Onorato1754d742016-11-21 17:51:35 -080026#include <utils/SystemClock.h>
27
Joe Onorato1754d742016-11-21 17:51:35 -080028#include <dirent.h>
Joe Onorato1754d742016-11-21 17:51:35 -080029#include <errno.h>
Yi Jinb592e3b2018-02-01 15:17:04 -080030#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/types.h>
Joe Onorato1754d742016-11-21 17:51:35 -080033
34/**
35 * The directory where the incident reports are stored.
36 */
Yi Jinadd11e92017-07-30 16:10:07 -070037static const char* INCIDENT_DIRECTORY = "/data/misc/incidents/";
Joe Onorato1754d742016-11-21 17:51:35 -080038
Yi Jin0a3406f2017-06-22 19:23:11 -070039// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -080040ReportRequest::ReportRequest(const IncidentReportArgs& a,
Yi Jinb592e3b2018-02-01 15:17:04 -080041 const sp<IIncidentReportStatusListener>& l, int f)
42 : args(a), listener(l), fd(f), err(NO_ERROR) {}
Joe Onorato1754d742016-11-21 17:51:35 -080043
Yi Jinb592e3b2018-02-01 15:17:04 -080044ReportRequest::~ReportRequest() {
Yi Jin22769e02017-10-16 14:42:50 -070045 if (fd >= 0) {
46 // clean up the opened file descriptor
47 close(fd);
48 }
Joe Onorato1754d742016-11-21 17:51:35 -080049}
50
Yi Jinb592e3b2018-02-01 15:17:04 -080051bool ReportRequest::ok() { return fd >= 0 && err == NO_ERROR; }
Yi Jinedfd5bb2017-09-06 17:09:11 -070052
Joe Onorato1754d742016-11-21 17:51:35 -080053// ================================================================================
54ReportRequestSet::ReportRequestSet()
Yi Jinb592e3b2018-02-01 15:17:04 -080055 : mRequests(), mSections(), mMainFd(-1), mMainDest(-1), mMetadata(), mSectionStats() {}
Joe Onorato1754d742016-11-21 17:51:35 -080056
Yi Jinb592e3b2018-02-01 15:17:04 -080057ReportRequestSet::~ReportRequestSet() {}
Joe Onorato1754d742016-11-21 17:51:35 -080058
Yi Jinadd11e92017-07-30 16:10:07 -070059// TODO: dedup on exact same args and fd, report the status back to listener!
Yi Jinb592e3b2018-02-01 15:17:04 -080060void ReportRequestSet::add(const sp<ReportRequest>& request) {
Joe Onorato1754d742016-11-21 17:51:35 -080061 mRequests.push_back(request);
Yi Jinadd11e92017-07-30 16:10:07 -070062 mSections.merge(request->args);
Yi Jin329130b2018-02-09 16:47:47 -080063 mMetadata.set_request_size(mMetadata.request_size() + 1);
Joe Onorato1754d742016-11-21 17:51:35 -080064}
65
Yi Jinb592e3b2018-02-01 15:17:04 -080066void ReportRequestSet::setMainFd(int fd) {
Joe Onorato1754d742016-11-21 17:51:35 -080067 mMainFd = fd;
Yi Jin329130b2018-02-09 16:47:47 -080068 mMetadata.set_use_dropbox(fd > 0);
Joe Onorato1754d742016-11-21 17:51:35 -080069}
70
Yi Jinb592e3b2018-02-01 15:17:04 -080071void ReportRequestSet::setMainDest(int dest) {
Yi Jin3ec5cc72018-01-26 13:42:43 -080072 mMainDest = dest;
Yi Jin329130b2018-02-09 16:47:47 -080073 PrivacySpec spec = PrivacySpec::new_spec(dest);
74 switch (spec.dest) {
75 case android::os::DEST_AUTOMATIC:
76 mMetadata.set_dest(IncidentMetadata_Destination_AUTOMATIC);
77 break;
78 case android::os::DEST_EXPLICIT:
79 mMetadata.set_dest(IncidentMetadata_Destination_EXPLICIT);
80 break;
81 case android::os::DEST_LOCAL:
82 mMetadata.set_dest(IncidentMetadata_Destination_LOCAL);
83 break;
84 }
Yi Jin3ec5cc72018-01-26 13:42:43 -080085}
86
Yi Jinb592e3b2018-02-01 15:17:04 -080087bool ReportRequestSet::containsSection(int id) { return mSections.containsSection(id); }
Joe Onorato1754d742016-11-21 17:51:35 -080088
Yi Jinb592e3b2018-02-01 15:17:04 -080089IncidentMetadata::SectionStats* ReportRequestSet::sectionStats(int id) {
Yi Jin329130b2018-02-09 16:47:47 -080090 if (mSectionStats.find(id) == mSectionStats.end()) {
91 auto stats = mMetadata.add_sections();
92 stats->set_id(id);
93 mSectionStats[id] = stats;
94 }
95 return mSectionStats[id];
96}
97
Joe Onorato1754d742016-11-21 17:51:35 -080098// ================================================================================
Yi Jinadd11e92017-07-30 16:10:07 -070099Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
100
Yi Jinb592e3b2018-02-01 15:17:04 -0800101Reporter::Reporter(const char* directory) : batch() {
Joe Onorato1754d742016-11-21 17:51:35 -0800102 char buf[100];
103
104 // TODO: Make the max size smaller for user builds.
105 mMaxSize = 100 * 1024 * 1024;
106 mMaxCount = 100;
107
Yi Jinadd11e92017-07-30 16:10:07 -0700108 // string ends up with '/' is a directory
109 String8 dir = String8(directory);
110 if (directory[dir.size() - 1] != '/') dir += "/";
111 mIncidentDirectory = dir.string();
112
Joe Onorato1754d742016-11-21 17:51:35 -0800113 // There can't be two at the same time because it's on one thread.
114 mStartTime = time(NULL);
Yi Jinadd11e92017-07-30 16:10:07 -0700115 strftime(buf, sizeof(buf), "incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
116 mFilename = mIncidentDirectory + buf;
Joe Onorato1754d742016-11-21 17:51:35 -0800117}
118
Yi Jinb592e3b2018-02-01 15:17:04 -0800119Reporter::~Reporter() {}
Joe Onorato1754d742016-11-21 17:51:35 -0800120
Yi Jinb592e3b2018-02-01 15:17:04 -0800121Reporter::run_report_status_t Reporter::runReport() {
Joe Onorato1754d742016-11-21 17:51:35 -0800122 status_t err = NO_ERROR;
123 bool needMainFd = false;
124 int mainFd = -1;
Yi Jin3ec5cc72018-01-26 13:42:43 -0800125 int mainDest = -1;
Yi Jinedfd5bb2017-09-06 17:09:11 -0700126 HeaderSection headers;
Yi Jin329130b2018-02-09 16:47:47 -0800127 MetadataSection metadataSection;
Joe Onorato1754d742016-11-21 17:51:35 -0800128
129 // See if we need the main file
Yi Jinb592e3b2018-02-01 15:17:04 -0800130 for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800131 if ((*it)->fd < 0 && mainFd < 0) {
132 needMainFd = true;
Yi Jin3ec5cc72018-01-26 13:42:43 -0800133 mainDest = (*it)->args.dest();
Joe Onorato1754d742016-11-21 17:51:35 -0800134 break;
135 }
136 }
137 if (needMainFd) {
138 // Create the directory
Yi Jinadd11e92017-07-30 16:10:07 -0700139 if (!isTest) err = create_directory(mIncidentDirectory);
Joe Onorato1754d742016-11-21 17:51:35 -0800140 if (err != NO_ERROR) {
Yi Jinedfd5bb2017-09-06 17:09:11 -0700141 goto DONE;
Joe Onorato1754d742016-11-21 17:51:35 -0800142 }
143
144 // If there are too many files in the directory (for whatever reason),
145 // delete the oldest ones until it's under the limit. Doing this first
146 // does mean that we can go over, so the max size is not a hard limit.
Yi Jinadd11e92017-07-30 16:10:07 -0700147 if (!isTest) clean_directory(mIncidentDirectory, mMaxSize, mMaxCount);
Joe Onorato1754d742016-11-21 17:51:35 -0800148
149 // Open the file.
150 err = create_file(&mainFd);
151 if (err != NO_ERROR) {
Yi Jinedfd5bb2017-09-06 17:09:11 -0700152 goto DONE;
Joe Onorato1754d742016-11-21 17:51:35 -0800153 }
154
155 // Add to the set
156 batch.setMainFd(mainFd);
Yi Jin3ec5cc72018-01-26 13:42:43 -0800157 batch.setMainDest(mainDest);
Joe Onorato1754d742016-11-21 17:51:35 -0800158 }
159
160 // Tell everyone that we're starting.
Yi Jinb592e3b2018-02-01 15:17:04 -0800161 for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800162 if ((*it)->listener != NULL) {
163 (*it)->listener->onReportStarted();
164 }
165 }
166
167 // Write the incident headers
Yi Jinedfd5bb2017-09-06 17:09:11 -0700168 headers.Execute(&batch);
Joe Onorato1754d742016-11-21 17:51:35 -0800169
170 // For each of the report fields, see if we need it, and if so, execute the command
171 // and report to those that care that we're doing it.
Yi Jinb592e3b2018-02-01 15:17:04 -0800172 for (const Section** section = SECTION_LIST; *section; section++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800173 const int id = (*section)->id;
Yi Jinadd11e92017-07-30 16:10:07 -0700174 if (this->batch.containsSection(id)) {
Yi Jinf32af482017-08-11 15:00:49 -0700175 ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
Yi Jinb592e3b2018-02-01 15:17:04 -0800176 for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800177 if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
Yi Jinb592e3b2018-02-01 15:17:04 -0800178 (*it)->listener->onReportSectionStatus(
179 id, IIncidentReportStatusListener::STATUS_STARTING);
Joe Onorato1754d742016-11-21 17:51:35 -0800180 }
181 }
182
183 // Execute - go get the data and write it into the file descriptors.
Yi Jin329130b2018-02-09 16:47:47 -0800184 auto stats = batch.sectionStats(id);
185 int64_t startTime = uptimeMillis();
Joe Onorato1754d742016-11-21 17:51:35 -0800186 err = (*section)->Execute(&batch);
Yi Jin329130b2018-02-09 16:47:47 -0800187 int64_t endTime = uptimeMillis();
188
189 stats->set_success(err == NO_ERROR);
190 stats->set_exec_duration_ms(endTime - startTime);
Joe Onorato1754d742016-11-21 17:51:35 -0800191 if (err != NO_ERROR) {
Yi Jina5c5e8a2017-09-27 18:24:58 -0700192 ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
Yi Jinb592e3b2018-02-01 15:17:04 -0800193 (*section)->name.string(), id, strerror(-err));
Yi Jinedfd5bb2017-09-06 17:09:11 -0700194 goto DONE;
Joe Onorato1754d742016-11-21 17:51:35 -0800195 }
196
Yi Jinb592e3b2018-02-01 15:17:04 -0800197 // Notify listener of starting
198 for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800199 if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
Yi Jinb592e3b2018-02-01 15:17:04 -0800200 (*it)->listener->onReportSectionStatus(
201 id, IIncidentReportStatusListener::STATUS_FINISHED);
Joe Onorato1754d742016-11-21 17:51:35 -0800202 }
203 }
Yi Jinf32af482017-08-11 15:00:49 -0700204 ALOGD("Finish incident report section %d '%s'", id, (*section)->name.string());
Joe Onorato1754d742016-11-21 17:51:35 -0800205 }
206 }
207
Yi Jinedfd5bb2017-09-06 17:09:11 -0700208DONE:
Yi Jin329130b2018-02-09 16:47:47 -0800209 // Reports the metdadata when taking the incident report.
210 if (!isTest) metadataSection.Execute(&batch);
211
Joe Onorato1754d742016-11-21 17:51:35 -0800212 // Close the file.
213 if (mainFd >= 0) {
214 close(mainFd);
215 }
216
217 // Tell everyone that we're done.
Yi Jinb592e3b2018-02-01 15:17:04 -0800218 for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800219 if ((*it)->listener != NULL) {
220 if (err == NO_ERROR) {
221 (*it)->listener->onReportFinished();
222 } else {
223 (*it)->listener->onReportFailed();
224 }
225 }
226 }
227
228 // Put the report into dropbox.
229 if (needMainFd && err == NO_ERROR) {
230 sp<DropBoxManager> dropbox = new DropBoxManager();
231 Status status = dropbox->addFile(String16("incident"), mFilename, 0);
232 ALOGD("Incident report done. dropbox status=%s\n", status.toString8().string());
233 if (!status.isOk()) {
234 return REPORT_NEEDS_DROPBOX;
235 }
236
237 // If the status was ok, delete the file. If not, leave it around until the next
238 // boot or the next checkin. If the directory gets too big older files will
239 // be rotated out.
Yi Jinb592e3b2018-02-01 15:17:04 -0800240 if (!isTest) unlink(mFilename.c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800241 }
242
243 return REPORT_FINISHED;
244}
245
246/**
247 * Create our output file and set the access permissions to -rw-rw----
248 */
Yi Jinb592e3b2018-02-01 15:17:04 -0800249status_t Reporter::create_file(int* fd) {
Joe Onorato1754d742016-11-21 17:51:35 -0800250 const char* filename = mFilename.c_str();
251
Yi Jinadd11e92017-07-30 16:10:07 -0700252 *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
Joe Onorato1754d742016-11-21 17:51:35 -0800253 if (*fd < 0) {
254 ALOGE("Couldn't open incident file: %s (%s)", filename, strerror(errno));
255 return -errno;
256 }
257
258 // Override umask. Not super critical. If it fails go on with life.
259 chmod(filename, 0660);
260
Yi Jin4bab3a12018-01-10 16:50:59 -0800261 if (chown(filename, AID_INCIDENTD, AID_INCIDENTD)) {
Joe Onorato1754d742016-11-21 17:51:35 -0800262 ALOGE("Unable to change ownership of incident file %s: %s\n", filename, strerror(errno));
263 status_t err = -errno;
264 unlink(mFilename.c_str());
265 return err;
266 }
267
268 return NO_ERROR;
269}
270
Yi Jinb592e3b2018-02-01 15:17:04 -0800271Reporter::run_report_status_t Reporter::upload_backlog() {
Joe Onorato1754d742016-11-21 17:51:35 -0800272 DIR* dir;
273 struct dirent* entry;
274 struct stat st;
Yi Jinadd11e92017-07-30 16:10:07 -0700275 status_t err;
Joe Onorato1754d742016-11-21 17:51:35 -0800276
Yi Jinf32af482017-08-11 15:00:49 -0700277 ALOGD("Start uploading backlogs in %s", INCIDENT_DIRECTORY);
Yi Jinadd11e92017-07-30 16:10:07 -0700278 if ((err = create_directory(INCIDENT_DIRECTORY)) != NO_ERROR) {
279 ALOGE("directory doesn't exist: %s", strerror(-err));
280 return REPORT_FINISHED;
281 }
282
283 if ((dir = opendir(INCIDENT_DIRECTORY)) == NULL) {
284 ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY);
Joe Onorato1754d742016-11-21 17:51:35 -0800285 return REPORT_NEEDS_DROPBOX;
286 }
287
Joe Onorato1754d742016-11-21 17:51:35 -0800288 sp<DropBoxManager> dropbox = new DropBoxManager();
289
290 // Enumerate, count and add up size
Yi Jinf32af482017-08-11 15:00:49 -0700291 int count = 0;
Joe Onorato1754d742016-11-21 17:51:35 -0800292 while ((entry = readdir(dir)) != NULL) {
293 if (entry->d_name[0] == '.') {
294 continue;
295 }
Yi Jinadd11e92017-07-30 16:10:07 -0700296 String8 filename = String8(INCIDENT_DIRECTORY) + entry->d_name;
Joe Onorato1754d742016-11-21 17:51:35 -0800297 if (stat(filename.string(), &st) != 0) {
298 ALOGE("Unable to stat file %s", filename.string());
299 continue;
300 }
301 if (!S_ISREG(st.st_mode)) {
302 continue;
303 }
304
305 Status status = dropbox->addFile(String16("incident"), filename.string(), 0);
306 ALOGD("Incident report done. dropbox status=%s\n", status.toString8().string());
307 if (!status.isOk()) {
308 return REPORT_NEEDS_DROPBOX;
309 }
310
311 // If the status was ok, delete the file. If not, leave it around until the next
312 // boot or the next checkin. If the directory gets too big older files will
313 // be rotated out.
314 unlink(filename.string());
Yi Jinf32af482017-08-11 15:00:49 -0700315 count++;
Joe Onorato1754d742016-11-21 17:51:35 -0800316 }
Yi Jinf32af482017-08-11 15:00:49 -0700317 ALOGD("Successfully uploaded %d files to Dropbox.", count);
Joe Onorato1754d742016-11-21 17:51:35 -0800318 closedir(dir);
319
320 return REPORT_FINISHED;
321}