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

Commit bab22bc8 authored by Adam Bookatz's avatar Adam Bookatz Committed by Android (Google) Code Review
Browse files

Merge "Statsd can dump data as proto to bugreport"

parents 8d45688b ff71cade
Loading
Loading
Loading
Loading
+26 −13
Original line number Diff line number Diff line
@@ -276,22 +276,21 @@ void StatsLogProcessor::dumpStates(int out, bool verbose) {
 */
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                     const bool include_current_partial_bucket,
                                     const bool erase_data,
                                     const DumpReportReason dumpReportReason,
                                     vector<uint8_t>* outData) {
                                     ProtoOutputStream* proto) {
    std::lock_guard<std::mutex> lock(mMetricsMutex);

    ProtoOutputStream proto;

    // Start of ConfigKey.
    uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
    proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
    proto.end(configKeyToken);
    uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
    proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
    proto->end(configKeyToken);
    // End of ConfigKey.

    // Then, check stats-data directory to see there's any file containing
    // ConfigMetricsReport from previous shutdowns to concatenate to reports.
    StorageManager::appendConfigMetricsReport(key, &proto);
    StorageManager::appendConfigMetricsReport(key, proto);

    auto it = mMetricsManagers.find(key);
    if (it != mMetricsManagers.end()) {
@@ -301,14 +300,27 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim

        // Start of ConfigMetricsReport (reports).
        uint64_t reportsToken =
                proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
                proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
        onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
                                    dumpReportReason, &proto);
        proto.end(reportsToken);
                                    erase_data, dumpReportReason, proto);
        proto->end(reportsToken);
        // End of ConfigMetricsReport (reports).
    } else {
        ALOGW("Config source %s does not exist", key.ToString().c_str());
    }
}

/*
 * onDumpReport dumps serialized ConfigMetricsReportList into outData.
 */
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                     const bool include_current_partial_bucket,
                                     const bool erase_data,
                                     const DumpReportReason dumpReportReason,
                                     vector<uint8_t>* outData) {
    ProtoOutputStream proto;
    onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
                 dumpReportReason, &proto);

    if (outData != nullptr) {
        outData->clear();
@@ -332,6 +344,7 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim
void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
                                                    const int64_t dumpTimeStampNs,
                                                    const bool include_current_partial_bucket,
                                                    const bool erase_data,
                                                    const DumpReportReason dumpReportReason,
                                                    ProtoOutputStream* proto) {
    // We already checked whether key exists in mMetricsManagers in
@@ -348,7 +361,7 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
    // First, fill in ConfigMetricsReport using current data on memory, which
    // starts from filling in StatsLogReport's.
    it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
                             &str_set, proto);
                             erase_data, &str_set, proto);

    // Fill in UidMap if there is at least one metric to report.
    // This skips the uid map if it's an empty config.
@@ -479,7 +492,7 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
    }
    ProtoOutputStream proto;
    onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
                                dumpReportReason, &proto);
                                true /* erase_data */, dumpReportReason, &proto);
    string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
         (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
    android::base::unique_fd fd(open(file_name.c_str(),
+5 −1
Original line number Diff line number Diff line
@@ -61,8 +61,11 @@ public:
    size_t GetMetricsSize(const ConfigKey& key) const;

    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                      const bool include_current_partial_bucket,
                      const bool include_current_partial_bucket, const bool erase_data,
                      const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                      const bool include_current_partial_bucket, const bool erase_data,
                      const DumpReportReason dumpReportReason, ProtoOutputStream* proto);

    /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
    void onAnomalyAlarmFired(
@@ -141,6 +144,7 @@ private:

    void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                     const bool include_current_partial_bucket,
                                     const bool erase_data,
                                     const DumpReportReason dumpReportReason,
                                     util::ProtoOutputStream* proto);

+54 −17
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@
using namespace android;

using android::base::StringPrintf;
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_MESSAGE;

namespace android {
namespace os {
@@ -58,6 +60,9 @@ constexpr const char* kOpUsage = "android:get_usage_stats";

#define STATS_SERVICE_DIR "/data/misc/stats-service"

// for StatsDataDumpProto
const int FIELD_ID_REPORTS_LIST = 1;

static binder::Status ok() {
    return binder::Status::ok();
}
@@ -224,23 +229,40 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
}

/**
 * Write debugging data about statsd.
 * Write data from statsd.
 * Format for statsdStats:  adb shell dumpsys stats --metadata [-v] [--proto]
 * Format for data report:  adb shell dumpsys stats [anything other than --metadata] [--proto]
 * Anything ending in --proto will be in proto format.
 * Anything without --metadata as the first argument will be report information.
 *     (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
 * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
 */
status_t StatsService::dump(int fd, const Vector<String16>& args) {
    if (!checkCallingPermission(String16(kPermissionDump))) {
        return PERMISSION_DENIED;
    }

    int lastArg = args.size() - 1;
    bool asProto = false;
    if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument
        asProto = true;
        lastArg--;
    }
    if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument
        // Request is to dump statsd stats.
        bool verbose = false;
    bool proto = false;
    if (args.size() > 0 && !args[0].compare(String16("-v"))) {
        if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) {
            verbose = true;
            lastArg--;
        }
        dumpStatsdStats(fd, verbose, asProto);
    } else {
        // Request is to dump statsd report data.
        if (asProto) {
            dumpIncidentSection(fd);
        } else {
            dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n");
        }
    if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) {
        proto = true;
    }

    dump_impl(fd, verbose, proto);

    return NO_ERROR;
}
@@ -248,7 +270,7 @@ status_t StatsService::dump(int fd, const Vector<String16>& args) {
/**
 * Write debugging data about statsd in text or proto format.
 */
void StatsService::dump_impl(int out, bool verbose, bool proto) {
void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) {
    if (proto) {
        vector<uint8_t> data;
        StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
@@ -261,6 +283,22 @@ void StatsService::dump_impl(int out, bool verbose, bool proto) {
    }
}

/**
 * Write stats report data in StatsDataDumpProto incident section format.
 */
void StatsService::dumpIncidentSection(int out) {
    ProtoOutputStream proto;
    for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
        uint64_t reportsListToken =
                proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
        mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
                                 true /* includeCurrentBucket */, false /* erase_data */,
                                 ADB_DUMP, &proto);
        proto.end(reportsListToken);
        proto.flush(out);
    }
}

/**
 * Implementation of the adb shell cmd stats command.
 */
@@ -283,7 +321,7 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
        }

        if (!args[0].compare(String8("dump-report"))) {
            return cmd_dump_report(out, err, args);
            return cmd_dump_report(out, args);
        }

        if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
@@ -546,7 +584,7 @@ status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& arg
    return UNKNOWN_ERROR;
}

status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
    if (mProcessor != nullptr) {
        int argCount = args.size();
        bool good = false;
@@ -589,14 +627,13 @@ status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>&
        if (good) {
            vector<uint8_t> data;
            mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
                                     includeCurrentBucket, ADB_DUMP, &data);
                                     includeCurrentBucket, true /* erase_data */, ADB_DUMP, &data);
            if (proto) {
                for (size_t i = 0; i < data.size(); i ++) {
                    dprintf(out, "%c", data[i]);
                }
            } else {
                dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
                dprintf(out, "See the StatsLogReport in logcat...\n");
                dprintf(out, "Non-proto stats data dump not currently supported.\n");
            }
            return android::OK;
        } else {
@@ -888,7 +925,7 @@ Status StatsService::getData(int64_t key, const String16& packageName, vector<ui
    VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
    ConfigKey configKey(ipc->getCallingUid(), key);
    mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
                             GET_DATA_CALLED, output);
                             true /* erase_data */, GET_DATA_CALLED, output);
    return Status::ok();
}

+8 −3
Original line number Diff line number Diff line
@@ -213,9 +213,14 @@ private:
                                         uint32_t serial);

    /**
     * Text or proto output of dumpsys.
     * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto.
     */
    void dump_impl(int outFd, bool verbose, bool proto);
    void dumpIncidentSection(int outFd);

    /**
     * Text or proto output of statsdStats dumpsys.
     */
    void dumpStatsdStats(int outFd, bool verbose, bool proto);

    /**
     * Print usage information for the commands
@@ -240,7 +245,7 @@ private:
    /**
     * Print the event log.
     */
    status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
    status_t cmd_dump_report(int outFd, const Vector<String8>& args);

    /**
     * Print the mapping of uids to package names.
+3 −1
Original line number Diff line number Diff line
@@ -82,7 +82,9 @@ int main(int /*argc*/, char** /*argv*/) {

    // Create the service
    gStatsService = new StatsService(looper);
    if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
    if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
                IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
            != 0) {
        ALOGE("Failed to add service as AIDL service");
        return -1;
    }
Loading