Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73287d1a authored by Mike Ma's avatar Mike Ma Committed by Android (Google) Code Review
Browse files

Merge "Incident Report Extension API"

parents 458fbcba 643de923
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -409,6 +409,7 @@ filegroup {
filegroup {
    name: "libincident_aidl",
    srcs: [
        "core/java/android/os/IIncidentDumpCallback.aidl",
        "core/java/android/os/IIncidentManager.aidl",
        "core/java/android/os/IIncidentReportStatusListener.aidl",
    ],
+51 −4
Original line number Diff line number Diff line
@@ -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,
+14 −2
Original line number Diff line number Diff line
@@ -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.
+59 −43
Original line number Diff line number Diff line
@@ -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) {
+10 −2
Original line number Diff line number Diff line
@@ -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();
};
Loading