/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "incidentd_util.h" #include "FdBuffer.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/IIncidentDumpCallback.h> #include <android/os/IncidentReportArgs.h> #include <android/util/protobuf.h> #include <map> #include <string> #include <vector> #include <time.h> #include <stdarg.h> namespace android { namespace os { namespace incidentd { using namespace std; using namespace android::content; using namespace android::os; class BringYourOwnSection; class Section; // ================================================================================ class ReportRequest : public virtual RefBase { public: IncidentReportArgs args; 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; sp<IIncidentReportStatusListener> getListener() { return mListener; } int getFd(); int setPersistedFd(int fd); status_t initGzipIfNecessary(); void closeFd(); private: sp<IIncidentReportStatusListener> mListener; int mFd; bool mIsStreaming; status_t mStatus; pid_t mZipPid; Fpipe mZipPipe; }; // ================================================================================ class ReportBatch : public virtual RefBase { public: ReportBatch(); virtual ~ReportBatch(); // 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. /** * Schedule a report for the "main" report, where it will be delivered to * the uploaders and/or dropbox. */ void addPersistedReport(const IncidentReportArgs& args); /** * 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); /** * 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. */ 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); /** * Remove all of the broadcast (persisted) requests. */ void clearPersistedRequests(); /** * Move the streaming requests in this batch to that batch. After this call there * will be no streaming requests in this batch. */ void transferStreamingRequests(const sp<ReportBatch>& that); /** * Move the persisted requests in this batch to that batch. After this call there * will be no streaming requests in this batch. */ void transferPersistedRequests(const sp<ReportBatch>& that); /** * 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: map<ComponentName, sp<ReportRequest>> mPersistedRequests; vector<sp<ReportRequest>> mStreamingRequests; }; // ================================================================================ 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: Reporter(const sp<WorkDirectory>& workDirectory, const sp<ReportBatch>& batch, const vector<BringYourOwnSection*>& registeredSections); virtual ~Reporter(); // Run the report as described in the batch and args parameters. void runReport(size_t* reportByteSize); private: sp<WorkDirectory> mWorkDirectory; 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(); }; } // namespace incidentd } // namespace os } // namespace android