1 /* 2 * Copyright (C) 2019 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 */ 16 17 #include "Log.h" 18 19 #include "WorkDirectory.h" 20 21 #include "proto_util.h" 22 #include "PrivacyFilter.h" 23 24 #include <google/protobuf/io/zero_copy_stream_impl.h> 25 #include <private/android_filesystem_config.h> 26 27 #include <iomanip> 28 #include <map> 29 #include <sstream> 30 #include <thread> 31 #include <vector> 32 33 #include <sys/stat.h> 34 #include <time.h> 35 #include <unistd.h> 36 #include <inttypes.h> 37 38 namespace android { 39 namespace os { 40 namespace incidentd { 41 42 using std::thread; 43 using google::protobuf::MessageLite; 44 using google::protobuf::RepeatedPtrField; 45 using google::protobuf::io::FileInputStream; 46 using google::protobuf::io::FileOutputStream; 47 48 /** 49 * Turn off to skip removing files for debugging. 50 */ 51 static const bool DO_UNLINK = true; 52 53 /** 54 * File extension for envelope files. 55 */ 56 static const string EXTENSION_ENVELOPE(".envelope"); 57 58 /** 59 * File extension for data files. 60 */ 61 static const string EXTENSION_DATA(".data"); 62 63 /** 64 * Send these reports to dropbox. 65 */ 66 const ComponentName DROPBOX_SENTINEL("android", "DROPBOX"); 67 68 /** metadata field id in IncidentProto */ 69 const int FIELD_ID_INCIDENT_METADATA = 2; 70 71 /** 72 * Read a protobuf from disk into the message. 73 */ 74 static status_t read_proto(MessageLite* msg, const string& filename) { 75 int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC); 76 if (fd < 0) { 77 return -errno; 78 } 79 80 FileInputStream stream(fd); 81 stream.SetCloseOnDelete(fd); 82 83 if (!msg->ParseFromZeroCopyStream(&stream)) { 84 return BAD_VALUE; 85 } 86 87 return stream.GetErrno(); 88 } 89 90 /** 91 * Write a protobuf to disk. 92 */ 93 static status_t write_proto(const MessageLite& msg, const string& filename) { 94 int fd = open(filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660); 95 if (fd < 0) { 96 return -errno; 97 } 98 99 FileOutputStream stream(fd); 100 stream.SetCloseOnDelete(fd); 101 102 if (!msg.SerializeToZeroCopyStream(&stream)) { 103 ALOGW("write_proto: error writing to %s", filename.c_str()); 104 return BAD_VALUE; 105 } 106 107 return stream.GetErrno(); 108 } 109 110 static string strip_extension(const string& filename) { 111 return filename.substr(0, filename.find('.')); 112 } 113 114 static bool ends_with(const string& str, const string& ending) { 115 if (str.length() >= ending.length()) { 116 return str.compare(str.length()-ending.length(), ending.length(), ending) == 0; 117 } else { 118 return false; 119 } 120 } 121 122 // Returns true if it was a valid timestamp. 123 static bool parse_timestamp_ns(const string& id, int64_t* result) { 124 char* endptr; 125 *result = strtoll(id.c_str(), &endptr, 10); 126 return id.length() != 0 && *endptr == '\0'; 127 } 128 129 static bool has_section(const ReportFileProto_Report& report, int section) { 130 const size_t sectionCount = report.section_size(); 131 for (int i = 0; i < sectionCount; i++) { 132 if (report.section(i) == section) { 133 return true; 134 } 135 } 136 return false; 137 } 138 139 status_t create_directory(const char* directory) { 140 struct stat st; 141 status_t err = NO_ERROR; 142 char* dir = strdup(directory); 143 144 // Skip first slash 145 char* d = dir + 1; 146 147 // Create directories, assigning them to the system user 148 bool last = false; 149 while (!last) { 150 d = strchr(d, '/'); 151 if (d != NULL) { 152 *d = '\0'; 153 } else { 154 last = true; 155 } 156 if (stat(dir, &st) == 0) { 157 if (!S_ISDIR(st.st_mode)) { 158 err = ALREADY_EXISTS; 159 goto done; 160 } 161 } else { 162 ALOGE("No such directory %s, something wrong.", dir); 163 err = -1; 164 goto done; 165 } 166 if (!last) { 167 *d++ = '/'; 168 } 169 } 170 171 // Ensure that the final directory is owned by the system with 0770. If it isn't 172 // we won't write into it. 173 if (stat(directory, &st) != 0) { 174 ALOGE("No incident reports today. Can't stat: %s", directory); 175 err = -errno; 176 goto done; 177 } 178 if ((st.st_mode & 0777) != 0770) { 179 ALOGE("No incident reports today. Mode is %0o on report directory %s", st.st_mode, 180 directory); 181 err = BAD_VALUE; 182 goto done; 183 } 184 if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) { 185 ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s", 186 st.st_uid, st.st_gid, directory); 187 err = BAD_VALUE; 188 goto done; 189 } 190 191 done: 192 free(dir); 193 return err; 194 } 195 196 void log_envelope(const ReportFileProto& envelope) { 197 ALOGD("Envelope: {"); 198 for (int i=0; i<envelope.report_size(); i++) { 199 ALOGD(" report {"); 200 ALOGD(" pkg=%s", envelope.report(i).pkg().c_str()); 201 ALOGD(" cls=%s", envelope.report(i).cls().c_str()); 202 ALOGD(" share_approved=%d", envelope.report(i).share_approved()); 203 ALOGD(" privacy_policy=%d", envelope.report(i).privacy_policy()); 204 ALOGD(" all_sections=%d", envelope.report(i).all_sections()); 205 for (int j=0; j<envelope.report(i).section_size(); j++) { 206 ALOGD(" section[%d]=%d", j, envelope.report(i).section(j)); 207 } 208 ALOGD(" }"); 209 } 210 ALOGD(" data_file=%s", envelope.data_file().c_str()); 211 ALOGD(" privacy_policy=%d", envelope.privacy_policy()); 212 ALOGD(" data_file_size=%lld", envelope.data_file_size()); 213 ALOGD(" completed=%d", envelope.completed()); 214 ALOGD("}"); 215 } 216 217 // ================================================================================ 218 struct WorkDirectoryEntry { 219 WorkDirectoryEntry(); 220 explicit WorkDirectoryEntry(const WorkDirectoryEntry& that); 221 ~WorkDirectoryEntry(); 222 223 string envelope; 224 string data; 225 int64_t timestampNs; 226 off_t size; 227 }; 228 229 WorkDirectoryEntry::WorkDirectoryEntry() 230 :envelope(), 231 data(), 232 size(0) { 233 } 234 235 WorkDirectoryEntry::WorkDirectoryEntry(const WorkDirectoryEntry& that) 236 :envelope(that.envelope), 237 data(that.data), 238 size(that.size) { 239 } 240 241 WorkDirectoryEntry::~WorkDirectoryEntry() { 242 } 243 244 // ================================================================================ 245 ReportFile::ReportFile(const sp<WorkDirectory>& workDirectory, int64_t timestampNs, 246 const string& envelopeFileName, const string& dataFileName) 247 :mWorkDirectory(workDirectory), 248 mTimestampNs(timestampNs), 249 mEnvelopeFileName(envelopeFileName), 250 mDataFileName(dataFileName), 251 mEnvelope(), 252 mDataFd(-1), 253 mError(NO_ERROR) { 254 // might get overwritten when we read but that's ok 255 mEnvelope.set_data_file(mDataFileName); 256 } 257 258 ReportFile::~ReportFile() { 259 if (mDataFd >= 0) { 260 close(mDataFd); 261 } 262 } 263 264 int64_t ReportFile::getTimestampNs() const { 265 return mTimestampNs; 266 } 267 268 void ReportFile::addReport(const IncidentReportArgs& args) { 269 // There is only one report per component. Merge into an existing one if necessary. 270 ReportFileProto_Report* report; 271 const int reportCount = mEnvelope.report_size(); 272 int i = 0; 273 for (; i < reportCount; i++) { 274 report = mEnvelope.mutable_report(i); 275 if (report->pkg() == args.receiverPkg() && report->cls() == args.receiverCls()) { 276 if (args.getPrivacyPolicy() < report->privacy_policy()) { 277 // Lower privacy policy (less restrictive) wins. 278 report->set_privacy_policy(args.getPrivacyPolicy()); 279 } 280 report->set_all_sections(report->all_sections() | args.all()); 281 for (int section: args.sections()) { 282 if (!has_section(*report, section)) { 283 report->add_section(section); 284 } 285 } 286 break; 287 } 288 } 289 if (i >= reportCount) { 290 report = mEnvelope.add_report(); 291 report->set_pkg(args.receiverPkg()); 292 report->set_cls(args.receiverCls()); 293 report->set_privacy_policy(args.getPrivacyPolicy()); 294 report->set_all_sections(args.all()); 295 for (int section: args.sections()) { 296 report->add_section(section); 297 } 298 } 299 300 for (const vector<uint8_t>& header: args.headers()) { 301 report->add_header(header.data(), header.size()); 302 } 303 } 304 305 void ReportFile::removeReport(const string& pkg, const string& cls) { 306 RepeatedPtrField<ReportFileProto_Report>* reports = mEnvelope.mutable_report(); 307 const int reportCount = reports->size(); 308 for (int i = 0; i < reportCount; i++) { 309 const ReportFileProto_Report& r = reports->Get(i); 310 if (r.pkg() == pkg && r.cls() == cls) { 311 reports->DeleteSubrange(i, 1); 312 return; 313 } 314 } 315 } 316 317 void ReportFile::removeReports(const string& pkg) { 318 RepeatedPtrField<ReportFileProto_Report>* reports = mEnvelope.mutable_report(); 319 const int reportCount = reports->size(); 320 for (int i = reportCount-1; i >= 0; i--) { 321 const ReportFileProto_Report& r = reports->Get(i); 322 if (r.pkg() == pkg) { 323 reports->DeleteSubrange(i, 1); 324 } 325 } 326 } 327 328 void ReportFile::setMetadata(const IncidentMetadata& metadata) { 329 *mEnvelope.mutable_metadata() = metadata; 330 } 331 332 void ReportFile::markCompleted() { 333 mEnvelope.set_completed(true); 334 } 335 336 status_t ReportFile::markApproved(const string& pkg, const string& cls) { 337 size_t const reportCount = mEnvelope.report_size(); 338 for (int reportIndex = 0; reportIndex < reportCount; reportIndex++) { 339 ReportFileProto_Report* report = mEnvelope.mutable_report(reportIndex); 340 if (report->pkg() == pkg && report->cls() == cls) { 341 report->set_share_approved(true); 342 return NO_ERROR; 343 } 344 } 345 return NAME_NOT_FOUND; 346 } 347 348 void ReportFile::setMaxPersistedPrivacyPolicy(int persistedPrivacyPolicy) { 349 mEnvelope.set_privacy_policy(persistedPrivacyPolicy); 350 } 351 352 status_t ReportFile::saveEnvelope() { 353 return save_envelope_impl(true); 354 } 355 356 status_t ReportFile::trySaveEnvelope() { 357 return save_envelope_impl(false); 358 } 359 360 status_t ReportFile::loadEnvelope() { 361 return load_envelope_impl(true); 362 } 363 364 status_t ReportFile::tryLoadEnvelope() { 365 return load_envelope_impl(false); 366 } 367 368 const ReportFileProto& ReportFile::getEnvelope() { 369 return mEnvelope; 370 } 371 372 status_t ReportFile::startWritingDataFile() { 373 if (mDataFd >= 0) { 374 ALOGW("ReportFile::startWritingDataFile called with the file already open: %s", 375 mDataFileName.c_str()); 376 return ALREADY_EXISTS; 377 } 378 mDataFd = open(mDataFileName.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660); 379 if (mDataFd < 0) { 380 return -errno; 381 } 382 return NO_ERROR; 383 } 384 385 void ReportFile::closeDataFile() { 386 if (mDataFd >= 0) { 387 mEnvelope.set_data_file_size(lseek(mDataFd, 0, SEEK_END)); 388 close(mDataFd); 389 mDataFd = -1; 390 } 391 } 392 393 status_t ReportFile::startFilteringData(int writeFd, const IncidentReportArgs& args) { 394 // Open data file. 395 int dataFd = open(mDataFileName.c_str(), O_RDONLY | O_CLOEXEC); 396 if (dataFd < 0) { 397 ALOGW("Error opening incident report '%s' %s", getDataFileName().c_str(), strerror(-errno)); 398 close(writeFd); 399 return -errno; 400 } 401 402 // Check that the size on disk is what we thought we wrote. 403 struct stat st; 404 if (fstat(dataFd, &st) != 0) { 405 ALOGW("Error running fstat incident report '%s' %s", getDataFileName().c_str(), 406 strerror(-errno)); 407 close(writeFd); 408 return -errno; 409 } 410 if (st.st_size != mEnvelope.data_file_size()) { 411 ALOGW("File size mismatch. Envelope says %" PRIi64 " bytes but data file is %" PRIi64 412 " bytes: %s", 413 (int64_t)mEnvelope.data_file_size(), st.st_size, mDataFileName.c_str()); 414 ALOGW("Removing incident report"); 415 mWorkDirectory->remove(this); 416 close(writeFd); 417 return BAD_VALUE; 418 } 419 420 status_t err; 421 422 for (const auto& report : mEnvelope.report()) { 423 for (const auto& header : report.header()) { 424 write_header_section(writeFd, 425 reinterpret_cast<const uint8_t*>(header.c_str()), header.size()); 426 } 427 } 428 429 if (mEnvelope.has_metadata()) { 430 write_section(writeFd, FIELD_ID_INCIDENT_METADATA, mEnvelope.metadata()); 431 } 432 433 err = filter_and_write_report(writeFd, dataFd, mEnvelope.privacy_policy(), args); 434 if (err != NO_ERROR) { 435 ALOGW("Error writing incident report '%s' to dropbox: %s", getDataFileName().c_str(), 436 strerror(-err)); 437 } 438 439 close(writeFd); 440 return NO_ERROR; 441 } 442 443 string ReportFile::getDataFileName() const { 444 return mDataFileName; 445 } 446 447 string ReportFile::getEnvelopeFileName() const { 448 return mEnvelopeFileName; 449 } 450 451 int ReportFile::getDataFileFd() { 452 return mDataFd; 453 } 454 455 void ReportFile::setWriteError(status_t err) { 456 mError = err; 457 } 458 459 status_t ReportFile::getWriteError() { 460 return mError; 461 } 462 463 string ReportFile::getId() { 464 return to_string(mTimestampNs); 465 } 466 467 status_t ReportFile::save_envelope_impl(bool cleanup) { 468 status_t err; 469 err = write_proto(mEnvelope, mEnvelopeFileName); 470 if (err != NO_ERROR) { 471 // If there was an error writing the envelope, then delete the whole thing. 472 if (cleanup) { 473 mWorkDirectory->remove(this); 474 } 475 return err; 476 } 477 return NO_ERROR; 478 } 479 480 status_t ReportFile::load_envelope_impl(bool cleanup) { 481 status_t err; 482 err = read_proto(&mEnvelope, mEnvelopeFileName); 483 if (err != NO_ERROR) { 484 // If there was an error reading the envelope, then delete the whole thing. 485 if (cleanup) { 486 mWorkDirectory->remove(this); 487 } 488 return err; 489 } 490 return NO_ERROR; 491 } 492 493 494 495 // ================================================================================ 496 // 497 498 WorkDirectory::WorkDirectory() 499 :mDirectory("/data/misc/incidents"), 500 mMaxFileCount(100), 501 mMaxDiskUsageBytes(100 * 1024 * 1024) { // Incident reports can take up to 100MB on disk. 502 // TODO: Should be a flag. 503 create_directory(mDirectory.c_str()); 504 } 505 506 WorkDirectory::WorkDirectory(const string& dir, int maxFileCount, long maxDiskUsageBytes) 507 :mDirectory(dir), 508 mMaxFileCount(maxFileCount), 509 mMaxDiskUsageBytes(maxDiskUsageBytes) { 510 create_directory(mDirectory.c_str()); 511 } 512 513 sp<ReportFile> WorkDirectory::createReportFile() { 514 unique_lock<mutex> lock(mLock); 515 status_t err; 516 517 clean_directory_locked(); 518 519 int64_t timestampNs = make_timestamp_ns_locked(); 520 string envelopeFileName = make_filename(timestampNs, EXTENSION_ENVELOPE); 521 string dataFileName = make_filename(timestampNs, EXTENSION_DATA); 522 523 sp<ReportFile> result = new ReportFile(this, timestampNs, envelopeFileName, dataFileName); 524 525 err = result->trySaveEnvelope(); 526 if (err != NO_ERROR) { 527 ALOGW("Can't save envelope file %s: %s", strerror(-errno), envelopeFileName.c_str()); 528 return nullptr; 529 } 530 531 return result; 532 } 533 534 status_t WorkDirectory::getReports(vector<sp<ReportFile>>* result, int64_t after) { 535 unique_lock<mutex> lock(mLock); 536 537 const bool DBG = true; 538 539 if (DBG) { 540 ALOGD("WorkDirectory::getReports"); 541 } 542 543 map<string,WorkDirectoryEntry> files; 544 get_directory_contents_locked(&files, after); 545 for (map<string,WorkDirectoryEntry>::iterator it = files.begin(); 546 it != files.end(); it++) { 547 sp<ReportFile> reportFile = new ReportFile(this, it->second.timestampNs, 548 it->second.envelope, it->second.data); 549 if (DBG) { 550 ALOGD(" %s", reportFile->getId().c_str()); 551 } 552 result->push_back(reportFile); 553 } 554 return NO_ERROR; 555 } 556 557 sp<ReportFile> WorkDirectory::getReport(const string& pkg, const string& cls, const string& id, 558 IncidentReportArgs* args) { 559 unique_lock<mutex> lock(mLock); 560 561 status_t err; 562 int64_t timestampNs; 563 if (!parse_timestamp_ns(id, ×tampNs)) { 564 return nullptr; 565 } 566 567 // Make the ReportFile object, and then see if it's valid and for pkg and cls. 568 sp<ReportFile> result = new ReportFile(this, timestampNs, 569 make_filename(timestampNs, EXTENSION_ENVELOPE), 570 make_filename(timestampNs, EXTENSION_DATA)); 571 572 err = result->tryLoadEnvelope(); 573 if (err != NO_ERROR) { 574 ALOGW("Can't open envelope file for report %s/%s %s", pkg.c_str(), cls.c_str(), id.c_str()); 575 return nullptr; 576 } 577 578 const ReportFileProto& envelope = result->getEnvelope(); 579 const size_t reportCount = envelope.report_size(); 580 for (int i = 0; i < reportCount; i++) { 581 const ReportFileProto_Report& report = envelope.report(i); 582 if (report.pkg() == pkg && report.cls() == cls) { 583 if (args != nullptr) { 584 get_args_from_report(args, report); 585 } 586 return result; 587 } 588 589 } 590 591 return nullptr; 592 } 593 594 bool WorkDirectory::hasMore(int64_t after) { 595 unique_lock<mutex> lock(mLock); 596 597 map<string,WorkDirectoryEntry> files; 598 get_directory_contents_locked(&files, after); 599 return files.size() > 0; 600 } 601 602 void WorkDirectory::commit(const sp<ReportFile>& report, const string& pkg, const string& cls) { 603 status_t err; 604 ALOGI("Committing report %s for %s/%s", report->getId().c_str(), pkg.c_str(), cls.c_str()); 605 606 unique_lock<mutex> lock(mLock); 607 608 // Load the envelope here inside the lock. 609 err = report->loadEnvelope(); 610 611 report->removeReport(pkg, cls); 612 613 delete_files_for_report_if_necessary(report); 614 } 615 616 void WorkDirectory::commitAll(const string& pkg) { 617 status_t err; 618 ALOGI("All reports for %s", pkg.c_str()); 619 620 unique_lock<mutex> lock(mLock); 621 622 map<string,WorkDirectoryEntry> files; 623 get_directory_contents_locked(&files, 0); 624 625 for (map<string,WorkDirectoryEntry>::iterator it = files.begin(); 626 it != files.end(); it++) { 627 sp<ReportFile> reportFile = new ReportFile(this, it->second.timestampNs, 628 it->second.envelope, it->second.data); 629 630 err = reportFile->loadEnvelope(); 631 if (err != NO_ERROR) { 632 continue; 633 } 634 635 reportFile->removeReports(pkg); 636 637 delete_files_for_report_if_necessary(reportFile); 638 } 639 } 640 641 void WorkDirectory::remove(const sp<ReportFile>& report) { 642 unique_lock<mutex> lock(mLock); 643 // Set this to false to leave files around for debugging. 644 if (DO_UNLINK) { 645 unlink(report->getDataFileName().c_str()); 646 unlink(report->getEnvelopeFileName().c_str()); 647 } 648 } 649 650 int64_t WorkDirectory::make_timestamp_ns_locked() { 651 // Guarantee that we don't have duplicate timestamps. 652 // This is a little bit lame, but since reports are created on the 653 // same thread and are kinda slow we'll seldomly actually hit the 654 // condition. The bigger risk is the clock getting reset and causing 655 // a collision. In that case, we'll just make incident reporting a 656 // little bit slower. Nobody will notice if we just loop until we 657 // have a unique file name. 658 int64_t timestampNs = 0; 659 do { 660 struct timespec spec; 661 if (timestampNs > 0) { 662 spec.tv_sec = 0; 663 spec.tv_nsec = 1; 664 nanosleep(&spec, nullptr); 665 } 666 clock_gettime(CLOCK_REALTIME, &spec); 667 timestampNs = (spec.tv_sec) * 1000 + spec.tv_nsec; 668 } while (file_exists_locked(timestampNs)); 669 return timestampNs; 670 } 671 672 /** 673 * It is required to hold the lock here so in case someone else adds it 674 * our result is still correct for the caller. 675 */ 676 bool WorkDirectory::file_exists_locked(int64_t timestampNs) { 677 const string filename = make_filename(timestampNs, EXTENSION_ENVELOPE); 678 struct stat st; 679 return stat(filename.c_str(), &st) == 0; 680 } 681 682 string WorkDirectory::make_filename(int64_t timestampNs, const string& extension) { 683 // Zero pad the timestamp so it can also be alpha sorted. 684 stringstream result; 685 result << mDirectory << '/' << setfill('0') << setw(20) << timestampNs << extension; 686 return result.str(); 687 } 688 689 off_t WorkDirectory::get_directory_contents_locked(map<string,WorkDirectoryEntry>* files, 690 int64_t after) { 691 DIR* dir; 692 struct dirent* entry; 693 694 if ((dir = opendir(mDirectory.c_str())) == NULL) { 695 ALOGE("Couldn't open incident directory: %s", mDirectory.c_str()); 696 return -1; 697 } 698 699 string dirbase(mDirectory); 700 if (mDirectory[dirbase.size() - 1] != '/') dirbase += "/"; 701 702 off_t totalSize = 0; 703 704 // Enumerate, count and add up size 705 while ((entry = readdir(dir)) != NULL) { 706 if (entry->d_name[0] == '.') { 707 continue; 708 } 709 string entryname = entry->d_name; // local to this dir 710 string filename = dirbase + entryname; // fully qualified 711 712 bool isEnvelope = ends_with(entryname, EXTENSION_ENVELOPE); 713 bool isData = ends_with(entryname, EXTENSION_DATA); 714 715 // If the file isn't one of our files, just ignore it. Otherwise, 716 // sum up the sizes. 717 if (isEnvelope || isData) { 718 string timestamp = strip_extension(entryname); 719 720 int64_t timestampNs; 721 if (!parse_timestamp_ns(timestamp, ×tampNs)) { 722 continue; 723 } 724 725 if (after == 0 || timestampNs > after) { 726 struct stat st; 727 if (stat(filename.c_str(), &st) != 0) { 728 ALOGE("Unable to stat file %s", filename.c_str()); 729 continue; 730 } 731 if (!S_ISREG(st.st_mode)) { 732 continue; 733 } 734 735 WorkDirectoryEntry& entry = (*files)[timestamp]; 736 if (isEnvelope) { 737 entry.envelope = filename; 738 } else if (isData) { 739 entry.data = filename; 740 } 741 entry.timestampNs = timestampNs; 742 entry.size += st.st_size; 743 totalSize += st.st_size; 744 } 745 } 746 } 747 748 closedir(dir); 749 750 // Now check if there are any data files that don't have envelope files. 751 // If there are, then just go ahead and delete them now. Don't wait for 752 // a cleaning. 753 754 if (DO_UNLINK) { 755 map<string,WorkDirectoryEntry>::iterator it = files->begin(); 756 while (it != files->end()) { 757 if (it->second.envelope.length() == 0) { 758 unlink(it->second.data.c_str()); 759 it = files->erase(it); 760 } else { 761 it++; 762 } 763 } 764 } 765 766 return totalSize; 767 } 768 769 void WorkDirectory::clean_directory_locked() { 770 DIR* dir; 771 struct dirent* entry; 772 struct stat st; 773 774 // Map of filename without extension to the entries about it. Conveniently, 775 // this also keeps the list sorted by filename, which is a timestamp. 776 map<string,WorkDirectoryEntry> files; 777 off_t totalSize = get_directory_contents_locked(&files, 0); 778 if (totalSize < 0) { 779 return; 780 } 781 int totalCount = files.size(); 782 783 // Count or size is less than max, then we're done. 784 if (totalSize < mMaxDiskUsageBytes && totalCount < mMaxFileCount) { 785 return; 786 } 787 788 // Remove files until we're under our limits. 789 if (DO_UNLINK) { 790 for (map<string, WorkDirectoryEntry>::const_iterator it = files.begin(); 791 it != files.end() && (totalSize >= mMaxDiskUsageBytes 792 || totalCount >= mMaxFileCount); 793 it++) { 794 unlink(it->second.envelope.c_str()); 795 unlink(it->second.data.c_str()); 796 totalSize -= it->second.size; 797 totalCount--; 798 } 799 } 800 } 801 802 void WorkDirectory::delete_files_for_report_if_necessary(const sp<ReportFile>& report) { 803 if (report->getEnvelope().report_size() == 0) { 804 ALOGI("Report %s is finished. Deleting from storage.", report->getId().c_str()); 805 if (DO_UNLINK) { 806 unlink(report->getDataFileName().c_str()); 807 unlink(report->getEnvelopeFileName().c_str()); 808 } 809 } 810 } 811 812 // ================================================================================ 813 void get_args_from_report(IncidentReportArgs* out, const ReportFileProto_Report& report) { 814 out->setPrivacyPolicy(report.privacy_policy()); 815 out->setAll(report.all_sections()); 816 out->setReceiverPkg(report.pkg()); 817 out->setReceiverCls(report.cls()); 818 819 const int sectionCount = report.section_size(); 820 for (int i = 0; i < sectionCount; i++) { 821 out->addSection(report.section(i)); 822 } 823 824 const int headerCount = report.header_size(); 825 for (int i = 0; i < headerCount; i++) { 826 const string& header = report.header(i); 827 vector<uint8_t> vec(header.begin(), header.end()); 828 out->addHeader(vec); 829 } 830 } 831 832 833 } // namespace incidentd 834 } // namespace os 835 } // namespace android 836 837