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

Commit 3343814a authored by Mike Ma's avatar Mike Ma Committed by android-build-merger
Browse files

Merge "Add an API to dump incident report for dumpstate" am: a11beeca

am: af1f91a1

Change-Id: If72f5dbe140ea5746288204e0de5275087d7709d
parents a75d6681 af1f91a1
Loading
Loading
Loading
Loading
+41 −17
Original line number Diff line number Diff line
@@ -197,6 +197,26 @@ parse_receiver_arg(const string& arg, string* pkg, string* cls)
    return true;
}

// ================================================================================
static int
stream_output(const int read_fd, const int write_fd) {
    while (true) {
        uint8_t buf[4096];
        ssize_t amt = TEMP_FAILURE_RETRY(read(read_fd, buf, sizeof(buf)));
        if (amt < 0) {
            break;
        } else if (amt == 0) {
            break;
        }

        ssize_t wamt = TEMP_FAILURE_RETRY(write(write_fd, buf, amt));
        if (wamt != amt) {
            return errno;
        }
    }
    return 0;
}

// ================================================================================
static void
usage(FILE* out)
@@ -208,11 +228,13 @@ usage(FILE* out)
    fprintf(out, "OPTIONS\n");
    fprintf(out, "  -l           list available sections\n");
    fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
    fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
    fprintf(out, "\n");
    fprintf(out, "and one of these destinations:\n");
    fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
    fprintf(out, "  -d           send the report into dropbox\n");
    fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
    fprintf(out, "  -u           print a full report to stdout for dumpstate to zip as a bug\n");
    fprintf(out, "               report. SECTION is ignored. Should only be called by dumpstate.\n");
    fprintf(out, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
    fprintf(out, "\n");
    fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
@@ -224,14 +246,14 @@ main(int argc, char** argv)
{
    Status status;
    IncidentReportArgs args;
    enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
    enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST, DEST_DUMPSTATE } destination = DEST_UNSET;
    int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
    string reason;
    string receiverArg;

    // Parse the args
    int opt;
    while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) {
    while ((opt = getopt(argc, argv, "bhdlp:r:s:u")) != -1) {
        switch (opt) {
            case 'h':
                usage(stdout);
@@ -253,6 +275,13 @@ main(int argc, char** argv)
                }
                destination = DEST_DROPBOX;
                break;
            case 'u':
                if (!(destination == DEST_UNSET || destination == DEST_DUMPSTATE)) {
                    usage(stderr);
                    return 1;
                }
                destination = DEST_DUMPSTATE;
                break;
            case 'p':
                privacyPolicy = get_privacy_policy(optarg);
                break;
@@ -355,21 +384,16 @@ main(int argc, char** argv)

        // Wait for the result and print out the data they send.
        //IPCThreadState::self()->joinThreadPool();

        while (true) {
            uint8_t buf[4096];
            ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
            if (amt < 0) {
                break;
            } else if (amt == 0) {
                break;
            }

            ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
            if (wamt != amt) {
                return errno;
            }
        return stream_output(fds[0], STDOUT_FILENO);
    } else if (destination == DEST_DUMPSTATE) {
        // Call into the service
        sp<StatusListener> listener(new StatusListener());
        status = service->reportIncidentToDumpstate(writeEnd, listener);
        if (!status.isOk()) {
            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
            return 1;
        }
        return stream_output(fds[0], STDOUT_FILENO);
    } else {
        status = service->reportIncident(args);
        if (!status.isOk()) {
+37 −42
Original line number Diff line number Diff line
@@ -46,12 +46,11 @@ enum {
#define DEFAULT_BYTES_SIZE_LIMIT (96 * 1024 * 1024)        // 96MB
#define DEFAULT_REFACTORY_PERIOD_MS (24 * 60 * 60 * 1000)  // 1 Day

// Skip these sections for dumpstate only. Dumpstate allows 10s max for each service to dump.
// Skip these sections (for dumpstate only)
// Skip logs (1100 - 1108) and traces (1200 - 1202) because they are already in the bug report.
// Skip 3018 because it takes too long.
#define SKIPPED_SECTIONS { 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \
                           1200, 1201, 1202, /* Native, hal, java traces */ \
                           3018  /* "meminfo -a --proto" */ }
#define SKIPPED_DUMPSTATE_SECTIONS { \
            1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \
            1200, 1201, 1202, /* Native, hal, java traces */ }

namespace android {
namespace os {
@@ -307,6 +306,39 @@ Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
    return Status::ok();
}

Status IncidentService::reportIncidentToDumpstate(const unique_fd& stream,
        const sp<IIncidentReportStatusListener>& listener) {
    uid_t caller = IPCThreadState::self()->getCallingUid();
    if (caller != AID_ROOT && caller != AID_SHELL) {
        ALOGW("Calling uid %d does not have permission: only ROOT or SHELL allowed", caller);
        return Status::fromExceptionCode(Status::EX_SECURITY, "Only ROOT or SHELL allowed");
    }

    ALOGD("Stream incident report to dumpstate");
    IncidentReportArgs incidentArgs;
    // Privacy policy for dumpstate incident reports is always EXPLICIT.
    incidentArgs.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT);

    int skipped[] = SKIPPED_DUMPSTATE_SECTIONS;
    for (const Section** section = SECTION_LIST; *section; section++) {
        const int id = (*section)->id;
        if (std::find(std::begin(skipped), std::end(skipped), id) == std::end(skipped)
                && !section_requires_specific_mention(id)) {
            incidentArgs.addSection(id);
        }
    }

    // The ReportRequest takes ownership of the fd, so we need to dup it.
    int fd = dup(stream.get());
    if (fd < 0) {
        return Status::fromStatusT(-errno);
    }

    mHandler->scheduleStreamingReport(incidentArgs, listener, fd);

    return Status::ok();
}

Status IncidentService::systemRunning() {
    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
        return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -551,43 +583,6 @@ status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<Str
    return NO_ERROR;
}

status_t IncidentService::dump(int fd, const Vector<String16>& args) {
    if (std::find(args.begin(), args.end(), String16("--proto")) == args.end()) {
        ALOGD("Skip dumping incident. Only proto format is supported.");
        dprintf(fd, "Incident dump only supports proto version.\n");
        return NO_ERROR;
    }

    ALOGD("Dump incident proto");
    IncidentReportArgs incidentArgs;
    incidentArgs.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT);
    int skipped[] = SKIPPED_SECTIONS;
    for (const Section** section = SECTION_LIST; *section; section++) {
        const int id = (*section)->id;
        if (std::find(std::begin(skipped), std::end(skipped), id) == std::end(skipped)
                && !section_requires_specific_mention(id)) {
            incidentArgs.addSection(id);
        }
    }

    if (!checkIncidentPermissions(incidentArgs).isOk()) {
        return PERMISSION_DENIED;
    }

    // The ReportRequest takes ownership of the fd, so we need to dup it.
    int fd1 = dup(fd);
    if (fd1 < 0) {
        return -errno;
    }

    // TODO: Remove this.  Someone even dumpstate, wanting to get an incident report
    // should use the API.  That will take making dumpstated call the API, which is a
    // good thing.  It also means it won't be subject to the timeout.
    mHandler->scheduleStreamingReport(incidentArgs, NULL, fd1);

    return NO_ERROR;
}

}  // namespace incidentd
}  // namespace os
}  // namespace android
+3 −1
Original line number Diff line number Diff line
@@ -123,6 +123,9 @@ public:
                                          const sp<IIncidentReportStatusListener>& listener,
                                          const unique_fd& stream);

    virtual Status reportIncidentToDumpstate(const unique_fd& stream,
            const sp<IIncidentReportStatusListener>& listener);

    virtual Status systemRunning();

    virtual Status getIncidentReportList(const String16& pkg, const String16& cls,
@@ -140,7 +143,6 @@ public:
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags) override;
    virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
    virtual status_t dump(int fd, const Vector<String16>& args);

private:
    sp<WorkDirectory> mWorkDirectory;
+1 −2
Original line number Diff line number Diff line
@@ -45,8 +45,7 @@ int main(int /*argc*/, char** /*argv*/) {

    // Create the service
    sp<IncidentService> service = new IncidentService(looper);
    if (defaultServiceManager()->addService(String16("incident"), service, false,
            IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO) != 0) {
    if (defaultServiceManager()->addService(String16("incident"), service) != 0) {
        ALOGE("Failed to add service");
        return -1;
    }
+9 −0
Original line number Diff line number Diff line
@@ -42,6 +42,15 @@ interface IIncidentManager {
            @nullable IIncidentReportStatusListener listener,
            FileDescriptor stream);

    /**
     * Takes a report with the given args, reporting status to the optional listener.
     * This should only be callable by dumpstate (enforced by callee).
     *
     * When the report is completed, the system report listener will be notified.
     */
    oneway void reportIncidentToDumpstate(FileDescriptor stream,
            @nullable IIncidentReportStatusListener listener);

    /**
     * Tell the incident daemon that the android system server is up and running.
     */