diff options
Diffstat (limited to 'cmds/incidentd/src')
-rw-r--r-- | cmds/incidentd/src/IncidentService.cpp | 55 | ||||
-rw-r--r-- | cmds/incidentd/src/IncidentService.h | 16 | ||||
-rw-r--r-- | cmds/incidentd/src/Reporter.cpp | 102 | ||||
-rw-r--r-- | cmds/incidentd/src/Reporter.h | 12 | ||||
-rw-r--r-- | cmds/incidentd/src/Section.cpp | 30 | ||||
-rw-r--r-- | cmds/incidentd/src/Section.h | 29 |
6 files changed, 181 insertions, 63 deletions
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index cfd77c2357cd..62312d1cccaa 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -123,14 +123,17 @@ static string build_uri(const string& pkg, const string& cls, const string& id) // ================================================================================ ReportHandler::ReportHandler(const sp<WorkDirectory>& workDirectory, - const sp<Broadcaster>& broadcaster, const sp<Looper>& handlerLooper, - const sp<Throttler>& throttler) + const sp<Broadcaster>& broadcaster, + const sp<Looper>& handlerLooper, + const sp<Throttler>& throttler, + const vector<BringYourOwnSection*>& registeredSections) :mLock(), mWorkDirectory(workDirectory), mBroadcaster(broadcaster), mHandlerLooper(handlerLooper), mBacklogDelay(DEFAULT_DELAY_NS), mThrottler(throttler), + mRegisteredSections(registeredSections), mBatch(new ReportBatch()) { } @@ -185,7 +188,7 @@ void ReportHandler::take_report() { return; } - sp<Reporter> reporter = new Reporter(mWorkDirectory, batch); + sp<Reporter> reporter = new Reporter(mWorkDirectory, batch, mRegisteredSections); // Take the report, which might take a while. More requests might queue // up while we're doing this, and we'll handle them in their next batch. @@ -237,7 +240,7 @@ IncidentService::IncidentService(const sp<Looper>& handlerLooper) { mWorkDirectory = new WorkDirectory(); mBroadcaster = new Broadcaster(mWorkDirectory); mHandler = new ReportHandler(mWorkDirectory, mBroadcaster, handlerLooper, - mThrottler); + mThrottler, mRegisteredSections); mBroadcaster->setHandler(mHandler); } @@ -327,6 +330,11 @@ Status IncidentService::reportIncidentToDumpstate(unique_fd stream, incidentArgs.addSection(id); } } + for (const Section* section : mRegisteredSections) { + if (!section_requires_specific_mention(section->id)) { + incidentArgs.addSection(section->id); + } + } // The ReportRequest takes ownership of the fd, so we need to dup it. int fd = dup(stream.get()); @@ -339,6 +347,45 @@ Status IncidentService::reportIncidentToDumpstate(unique_fd stream, return Status::ok(); } +Status IncidentService::registerSection(const int id, const String16& name16, + const sp<IIncidentDumpCallback>& callback) { + const char* name = String8(name16).c_str(); + ALOGI("Register section %d: %s", id, name); + if (callback == nullptr) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER); + } + const uid_t callingUid = IPCThreadState::self()->getCallingUid(); + for (int i = 0; i < mRegisteredSections.size(); i++) { + if (mRegisteredSections.at(i)->id == id) { + if (mRegisteredSections.at(i)->uid != callingUid) { + ALOGW("Error registering section %d: calling uid does not match", id); + return Status::fromExceptionCode(Status::EX_SECURITY); + } + mRegisteredSections.at(i) = new BringYourOwnSection(id, name, callingUid, callback); + return Status::ok(); + } + } + mRegisteredSections.push_back(new BringYourOwnSection(id, name, callingUid, callback)); + return Status::ok(); +} + +Status IncidentService::unregisterSection(const int id) { + ALOGI("Unregister section %d", id); + uid_t callingUid = IPCThreadState::self()->getCallingUid(); + for (auto it = mRegisteredSections.begin(); it != mRegisteredSections.end(); it++) { + if ((*it)->id == id) { + if ((*it)->uid != callingUid) { + ALOGW("Error unregistering section %d: calling uid does not match", id); + return Status::fromExceptionCode(Status::EX_SECURITY); + } + mRegisteredSections.erase(it); + return Status::ok(); + } + } + ALOGW("Section %d not found", id); + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); +} + Status IncidentService::systemRunning() { if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { return Status::fromExceptionCode(Status::EX_SECURITY, diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h index b2c7f233e11b..49fc566d71af 100644 --- a/cmds/incidentd/src/IncidentService.h +++ b/cmds/incidentd/src/IncidentService.h @@ -40,12 +40,16 @@ using namespace android::base; using namespace android::binder; using namespace android::os; +class BringYourOwnSection; + // ================================================================================ class ReportHandler : public MessageHandler { public: ReportHandler(const sp<WorkDirectory>& workDirectory, - const sp<Broadcaster>& broadcaster, const sp<Looper>& handlerLooper, - const sp<Throttler>& throttler); + const sp<Broadcaster>& broadcaster, + const sp<Looper>& handlerLooper, + const sp<Throttler>& throttler, + const vector<BringYourOwnSection*>& registeredSections); virtual ~ReportHandler(); virtual void handleMessage(const Message& message); @@ -79,6 +83,8 @@ private: nsecs_t mBacklogDelay; sp<Throttler> mThrottler; + const vector<BringYourOwnSection*>& mRegisteredSections; + sp<ReportBatch> mBatch; /** @@ -126,6 +132,11 @@ public: virtual Status reportIncidentToDumpstate(unique_fd stream, const sp<IIncidentReportStatusListener>& listener); + virtual Status registerSection(int id, const String16& name, + const sp<IIncidentDumpCallback>& callback); + + virtual Status unregisterSection(int id); + virtual Status systemRunning(); virtual Status getIncidentReportList(const String16& pkg, const String16& cls, @@ -149,6 +160,7 @@ private: sp<Broadcaster> mBroadcaster; sp<ReportHandler> mHandler; sp<Throttler> mThrottler; + vector<BringYourOwnSection*> mRegisteredSections; /** * Commands print out help. diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp index 02b6bbe6c9b1..aa40f85fd340 100644 --- a/cmds/incidentd/src/Reporter.cpp +++ b/cmds/incidentd/src/Reporter.cpp @@ -364,7 +364,6 @@ void ReportWriter::startSection(int sectionId) { mSectionBufferSuccess = false; mHadError = false; mSectionErrors.clear(); - } void ReportWriter::setSectionStats(const FdBuffer& buffer) { @@ -470,10 +469,13 @@ status_t ReportWriter::writeSection(const FdBuffer& buffer) { // ================================================================================ -Reporter::Reporter(const sp<WorkDirectory>& workDirectory, const sp<ReportBatch>& batch) +Reporter::Reporter(const sp<WorkDirectory>& workDirectory, + const sp<ReportBatch>& batch, + const vector<BringYourOwnSection*>& registeredSections) :mWorkDirectory(workDirectory), mWriter(batch), - mBatch(batch) { + mBatch(batch), + mRegisteredSections(registeredSections) { } Reporter::~Reporter() { @@ -580,50 +582,15 @@ void Reporter::runReport(size_t* reportByteSize) { // 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 sectionId = (*section)->id; - - // If nobody wants this section, skip it. - if (!mBatch->containsSection(sectionId)) { - continue; + if (execute_section(*section, &metadata, reportByteSize) != NO_ERROR) { + goto DONE; } + } - ALOGD("Start incident report section %d '%s'", sectionId, (*section)->name.string()); - IncidentMetadata::SectionStats* sectionMetadata = metadata.add_sections(); - - // Notify listener of starting - mBatch->forEachListener(sectionId, [sectionId](const auto& listener) { - listener->onReportSectionStatus( - sectionId, IIncidentReportStatusListener::STATUS_STARTING); - }); - - // Go get the data and write it into the file descriptors. - mWriter.startSection(sectionId); - err = (*section)->Execute(&mWriter); - mWriter.endSection(sectionMetadata); - - // Sections returning errors are fatal. Most errors should not be fatal. - if (err != NO_ERROR) { - mWriter.error((*section), err, "Section failed. Stopping report."); + for (const Section* section : mRegisteredSections) { + if (execute_section(section, &metadata, reportByteSize) != NO_ERROR) { goto DONE; } - - // The returned max data size is used for throttling too many incident reports. - (*reportByteSize) += sectionMetadata->report_size_bytes(); - - // For any requests that failed during this section, remove them now. We do this - // before calling back about section finished, so listeners do not erroniously get the - // impression that the section succeeded. But we do it here instead of inside - // writeSection so that the callback is done from a known context and not from the - // bowels of a section, where changing the batch could cause odd errors. - cancel_and_remove_failed_requests(); - - // Notify listener of finishing - mBatch->forEachListener(sectionId, [sectionId](const auto& listener) { - listener->onReportSectionStatus( - sectionId, IIncidentReportStatusListener::STATUS_FINISHED); - }); - - ALOGD("Finish incident report section %d '%s'", sectionId, (*section)->name.string()); } DONE: @@ -681,6 +648,55 @@ DONE: ALOGI("Done taking incident report err=%s", strerror(-err)); } +status_t Reporter::execute_section(const Section* section, IncidentMetadata* metadata, + size_t* reportByteSize) { + const int sectionId = section->id; + + // If nobody wants this section, skip it. + if (!mBatch->containsSection(sectionId)) { + return NO_ERROR; + } + + ALOGD("Start incident report section %d '%s'", sectionId, section->name.string()); + IncidentMetadata::SectionStats* sectionMetadata = metadata->add_sections(); + + // Notify listener of starting + mBatch->forEachListener(sectionId, [sectionId](const auto& listener) { + listener->onReportSectionStatus( + sectionId, IIncidentReportStatusListener::STATUS_STARTING); + }); + + // Go get the data and write it into the file descriptors. + mWriter.startSection(sectionId); + status_t err = section->Execute(&mWriter); + mWriter.endSection(sectionMetadata); + + // Sections returning errors are fatal. Most errors should not be fatal. + if (err != NO_ERROR) { + mWriter.error(section, err, "Section failed. Stopping report."); + return err; + } + + // The returned max data size is used for throttling too many incident reports. + (*reportByteSize) += sectionMetadata->report_size_bytes(); + + // For any requests that failed during this section, remove them now. We do this + // before calling back about section finished, so listeners do not erroniously get the + // impression that the section succeeded. But we do it here instead of inside + // writeSection so that the callback is done from a known context and not from the + // bowels of a section, where changing the batch could cause odd errors. + cancel_and_remove_failed_requests(); + + // Notify listener of finishing + mBatch->forEachListener(sectionId, [sectionId](const auto& listener) { + listener->onReportSectionStatus( + sectionId, IIncidentReportStatusListener::STATUS_FINISHED); + }); + + ALOGD("Finish incident report section %d '%s'", sectionId, section->name.string()); + return NO_ERROR; +} + void Reporter::cancel_and_remove_failed_requests() { // Handle a failure in the persisted file if (mPersistedFile != nullptr) { diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h index fb3961ab8b43..cbc8b136e7e3 100644 --- a/cmds/incidentd/src/Reporter.h +++ b/cmds/incidentd/src/Reporter.h @@ -21,6 +21,7 @@ #include "frameworks/base/core/proto/android/os/metadata.pb.h" #include <android/content/ComponentName.h> #include <android/os/IIncidentReportStatusListener.h> +#include <android/os/IIncidentDumpCallback.h> #include <android/os/IncidentReportArgs.h> #include <android/util/protobuf.h> @@ -39,6 +40,7 @@ using namespace std; using namespace android::content; using namespace android::os; +class BringYourOwnSection; class Section; // ================================================================================ @@ -122,7 +124,7 @@ public: void forEachStreamingRequest(const function<void (const sp<ReportRequest>&)>& func); /** - * Call func(request) for each file descriptor that has + * Call func(request) for each file descriptor. */ void forEachFd(int sectionId, const function<void (const sp<ReportRequest>&)>& func); @@ -251,7 +253,9 @@ private: // ================================================================================ class Reporter : public virtual RefBase { public: - Reporter(const sp<WorkDirectory>& workDirectory, const sp<ReportBatch>& batch); + Reporter(const sp<WorkDirectory>& workDirectory, + const sp<ReportBatch>& batch, + const vector<BringYourOwnSection*>& registeredSections); virtual ~Reporter(); @@ -263,6 +267,10 @@ private: ReportWriter mWriter; sp<ReportBatch> mBatch; sp<ReportFile> mPersistedFile; + const vector<BringYourOwnSection*>& mRegisteredSections; + + status_t execute_section(const Section* section, IncidentMetadata* metadata, + size_t* reportByteSize); void cancel_and_remove_failed_requests(); }; diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp index c9277a57bd07..2229e1c7ca07 100644 --- a/cmds/incidentd/src/Section.cpp +++ b/cmds/incidentd/src/Section.cpp @@ -267,7 +267,7 @@ static void* worker_thread_func(void* cookie) { signal(SIGPIPE, sigpipe_handler); WorkerThreadData* data = (WorkerThreadData*)cookie; - status_t err = data->section->BlockingCall(data->pipe.writeFd().get()); + status_t err = data->section->BlockingCall(data->pipe.writeFd()); { unique_lock<mutex> lock(data->lock); @@ -458,7 +458,7 @@ DumpsysSection::DumpsysSection(int id, const char* service, ...) DumpsysSection::~DumpsysSection() {} -status_t DumpsysSection::BlockingCall(int pipeWriteFd) const { +status_t DumpsysSection::BlockingCall(unique_fd& pipeWriteFd) const { // checkService won't wait for the service to show up like getService will. sp<IBinder> service = defaultServiceManager()->checkService(mService); @@ -467,7 +467,7 @@ status_t DumpsysSection::BlockingCall(int pipeWriteFd) const { return NAME_NOT_FOUND; } - service->dump(pipeWriteFd, mArgs); + service->dump(pipeWriteFd.get(), mArgs); return NO_ERROR; } @@ -526,7 +526,7 @@ static inline int32_t get4LE(uint8_t const* src) { return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); } -status_t LogSection::BlockingCall(int pipeWriteFd) const { +status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const { // Open log buffer and getting logs since last retrieved time if any. unique_ptr<logger_list, void (*)(logger_list*)> loggers( gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end() @@ -643,7 +643,7 @@ status_t LogSection::BlockingCall(int pipeWriteFd) const { } } gLastLogsRetrieved[mLogID] = lastTimestamp; - if (!proto.flush(pipeWriteFd) && errno == EPIPE) { + if (!proto.flush(pipeWriteFd.get()) && errno == EPIPE) { ALOGE("[%s] wrote to a broken pipe\n", this->name.string()); return EPIPE; } @@ -660,7 +660,7 @@ TombstoneSection::TombstoneSection(int id, const char* type, const int64_t timeo TombstoneSection::~TombstoneSection() {} -status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { +status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const { std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir); if (proc.get() == nullptr) { ALOGE("opendir /proc failed: %s\n", strerror(errno)); @@ -768,7 +768,7 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { dumpPipe.readFd().reset(); } - if (!proto.flush(pipeWriteFd) && errno == EPIPE) { + if (!proto.flush(pipeWriteFd.get()) && errno == EPIPE) { ALOGE("[%s] wrote to a broken pipe\n", this->name.string()); if (err != NO_ERROR) { return EPIPE; @@ -778,6 +778,22 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { return err; } +// ================================================================================ +BringYourOwnSection::BringYourOwnSection(int id, const char* customName, const uid_t callingUid, + const sp<IIncidentDumpCallback>& callback) + : WorkerThreadSection(id, REMOTE_CALL_TIMEOUT_MS), uid(callingUid), mCallback(callback) { + name = "registered "; + name += customName; +} + +BringYourOwnSection::~BringYourOwnSection() {} + +status_t BringYourOwnSection::BlockingCall(unique_fd& pipeWriteFd) const { + android::os::ParcelFileDescriptor pfd(std::move(pipeWriteFd)); + mCallback->onDumpSection(pfd); + return NO_ERROR; +} + } // namespace incidentd } // namespace os } // namespace android diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h index fcf12f7336fd..0bb9da9aac5b 100644 --- a/cmds/incidentd/src/Section.h +++ b/cmds/incidentd/src/Section.h @@ -23,6 +23,8 @@ #include <stdarg.h> #include <map> +#include <android/os/IIncidentDumpCallback.h> + #include <utils/String16.h> #include <utils/String8.h> #include <utils/Vector.h> @@ -89,7 +91,7 @@ public: virtual status_t Execute(ReportWriter* writer) const; - virtual status_t BlockingCall(int pipeWriteFd) const = 0; + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const = 0; }; /** @@ -117,7 +119,7 @@ public: DumpsysSection(int id, const char* service, ...); virtual ~DumpsysSection(); - virtual status_t BlockingCall(int pipeWriteFd) const; + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const; private: String16 mService; @@ -132,7 +134,7 @@ public: SystemPropertyDumpsysSection(int id, const char* service, ...); virtual ~SystemPropertyDumpsysSection(); - virtual status_t BlockingCall(int pipeWriteFd) const; + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const; private: String16 mService; @@ -153,7 +155,7 @@ public: LogSection(int id, const char* logID, ...); virtual ~LogSection(); - virtual status_t BlockingCall(int pipeWriteFd) const; + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const; private: log_id_t mLogID; @@ -169,12 +171,29 @@ public: TombstoneSection(int id, const char* type, int64_t timeoutMs = 120000 /* 2 minutes */); virtual ~TombstoneSection(); - virtual status_t BlockingCall(int pipeWriteFd) const; + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const; private: std::string mType; }; +/** + * Section that gets data from a registered dump callback. + */ +class BringYourOwnSection : public WorkerThreadSection { +public: + const uid_t uid; + + BringYourOwnSection(int id, const char* customName, const uid_t callingUid, + const sp<IIncidentDumpCallback>& callback); + virtual ~BringYourOwnSection(); + + virtual status_t BlockingCall(unique_fd& pipeWriteFd) const; + +private: + const sp<IIncidentDumpCallback>& mCallback; +}; + /** * These sections will not be generated when doing an 'all' report, either |