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

Commit 87d983cf authored by yro's avatar yro
Browse files

Write statsd configuration to disk and add cmd to clear it

Test: statsd, statsd_test
Change-Id: Iba37a7f295256d24969185bdde6cbf28f9b89a55
parent fb9ec66e
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#define DEBUG true
#include "Log.h"

#include "android-base/stringprintf.h"
#include "StatsService.h"
#include "config/ConfigKey.h"
#include "config/ConfigManager.h"
@@ -25,11 +26,11 @@
#include <android-base/file.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
#include <utils/String16.h>

#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -42,6 +43,7 @@ namespace os {
namespace statsd {

constexpr const char* kPermissionDump = "android.permission.DUMP";
#define STATS_SERVICE_DIR "/data/system/stats-service"

// ======================================================================
/**
@@ -206,6 +208,10 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
        if (!args[0].compare(String8("send-broadcast"))) {
            return cmd_trigger_broadcast(args);
        }

        if (!args[0].compare(String8("clear-config"))) {
            return cmd_remove_config_files(out);
        }
    }

    print_cmd_help(out);
@@ -223,6 +229,11 @@ void StatsService::print_cmd_help(FILE* out) {
    fprintf(out, "  Prints the UID, app name, version mapping.\n");
    fprintf(out, "\n");
    fprintf(out, "\n");
    fprintf(out, "usage: adb shell cmd stats clear-config \n");
    fprintf(out, "\n");
    fprintf(out, "  Removes all configs from disk.\n");
    fprintf(out, "\n");
    fprintf(out, "\n");
    fprintf(out, "usage: adb shell cmds stats pull-source [int] \n");
    fprintf(out, "\n");
    fprintf(out, "  Prints the output of a pulled metrics source (int indicates source)\n");
@@ -405,6 +416,27 @@ status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>
    return UNKNOWN_ERROR;
}

status_t StatsService::cmd_remove_config_files(FILE* out) {
    fprintf(out, "Trying to remove config files...\n");
    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
    if (dir == NULL) {
        fprintf(out, "No existing config files found exiting...\n");
        return NO_ERROR;
    }

    dirent* de;
    while ((de = readdir(dir.get()))) {
        char* name = de->d_name;
        if (name[0] == '.') continue;
        string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
        fprintf(out, "Deleting file %s\n", file_name.c_str());
        if (remove(file_name.c_str())) {
            fprintf(out, "Error deleting file %s\n", file_name.c_str());
        }
    }
    return NO_ERROR;
}

Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                      const vector<String16>& app) {
    if (DEBUG) ALOGD("StatsService::informAllUidData was called");
+5 −0
Original line number Diff line number Diff line
@@ -151,6 +151,11 @@ private:
     */
    status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);

    /**
     * Removes all configs stored on disk.
     */
    status_t cmd_remove_config_files(FILE* out);

    /**
     * Update a configuration.
     */
+1 −1
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ inline ostream& operator<<(ostream& os, const ConfigKey& config) {

/**
 * A hash function for ConfigKey so it can be used for unordered_map/set.
 * Unfortunately this hast to go in std namespace because C++ is fun!
 * Unfortunately this has to go in std namespace because C++ is fun!
 */
namespace std {

+91 −9
Original line number Diff line number Diff line
@@ -18,16 +18,23 @@

#include "stats_util.h"

#include <vector>

#include <android-base/file.h>
#include <dirent.h>
#include <stdio.h>
#include <vector>
#include "android-base/stringprintf.h"

namespace android {
namespace os {
namespace statsd {

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

static StatsdConfig build_fake_config();

using android::base::StringPrintf;
using std::unique_ptr;

ConfigManager::ConfigManager() {
}

@@ -35,8 +42,7 @@ ConfigManager::~ConfigManager() {
}

void ConfigManager::Startup() {
    // TODO: Implement me -- read from storage and call onto all of the listeners.
    // Instead, we'll just make a fake one.
    readConfigFromDisk();

    // this should be called from StatsService when it receives a statsd_config
    UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
@@ -52,7 +58,7 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
    // Why doesn't this work? mConfigs.insert({key, config});

    // Save to disk
    update_saved_configs();
    update_saved_configs(key, config);

    // Tell everyone
    for (auto& listener : mListeners) {
@@ -74,8 +80,8 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
        // Remove from map
        mConfigs.erase(it);

        // Save to disk
        update_saved_configs();
        // Remove from disk
        remove_saved_configs(key);

        // Tell everyone
        for (auto& listener : mListeners) {
@@ -85,6 +91,26 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
    // If we didn't find it, just quietly ignore it.
}

void ConfigManager::remove_saved_configs(const ConfigKey& key) {
    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
    if (dir == NULL) {
        ALOGD("no default config on disk");
        return;
    }
    string prefix = StringPrintf("%d-%s", key.GetUid(), key.GetName().c_str());
    dirent* de;
    while ((de = readdir(dir.get()))) {
        char* name = de->d_name;
        if (name[0] != '.' && strncmp(name, prefix.c_str(), prefix.size()) == 0) {
            if (remove(StringPrintf("%s/%d-%s", STATS_SERVICE_DIR, key.GetUid(),
                                    key.GetName().c_str())
                               .c_str()) != 0) {
                ALOGD("no file found");
            }
        }
    }
}

void ConfigManager::RemoveConfigs(int uid) {
    vector<ConfigKey> removed;

@@ -118,8 +144,64 @@ void ConfigManager::Dump(FILE* out) {
    }
}

void ConfigManager::update_saved_configs() {
    // TODO: Implement me -- write to disk.
void ConfigManager::readConfigFromDisk() {
    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
    if (dir == NULL) {
        ALOGD("no default config on disk");
        return;
    }

    dirent* de;
    while ((de = readdir(dir.get()))) {
        char* name = de->d_name;
        if (name[0] == '.') continue;
        ALOGD("file %s", name);

        int index = 0;
        int uid = 0;
        string configName;
        char* substr = strtok(name, "-");
        // Timestamp lives at index 2 but we skip parsing it as it's not needed.
        while (substr != nullptr && index < 2) {
            if (index) {
                uid = atoi(substr);
            } else {
                configName = substr;
            }
            index++;
        }
        if (index < 2) continue;
        string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
        ALOGD("full file %s", file_name.c_str());
        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
        if (fd != -1) {
            string content;
            if (android::base::ReadFdToString(fd, &content)) {
                StatsdConfig config;
                if (config.ParseFromString(content)) {
                    mConfigs[ConfigKey(uid, configName)] = config;
                    ALOGD("map key uid=%d|name=%s", uid, name);
                }
            }
            close(fd);
        }
    }
}

void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
    mkdir(STATS_SERVICE_DIR, S_IRWXU);
    string file_name = StringPrintf("%s/%d-%s-%ld", STATS_SERVICE_DIR, key.GetUid(),
                                    key.GetName().c_str(), time(nullptr));
    int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
    if (fd != -1) {
        const int numBytes = config.ByteSize();
        vector<uint8_t> buffer(numBytes);
        config.SerializeToArray(&buffer[0], numBytes);
        int result = write(fd, &buffer[0], numBytes);
        close(fd);
        bool wroteKey = (result == numBytes);
        ALOGD("wrote to file %d", wroteKey);
    }
}

static StatsdConfig build_fake_config() {
+12 −4
Original line number Diff line number Diff line
@@ -46,9 +46,7 @@ public:
    virtual ~ConfigManager();

    /**
     * Call to load the saved configs from disk.
     *
     * TODO: Implement me
     * Initialize ConfigListener by reading from disk and get updates.
     */
    void Startup();

@@ -95,7 +93,12 @@ private:
    /**
     * Save the configs to disk.
     */
    void update_saved_configs();
    void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);

    /**
     * Remove saved configs from disk.
     */
    void remove_saved_configs(const ConfigKey& key);

    /**
     * The Configs that have been set. Each config should
@@ -112,6 +115,11 @@ private:
     * The ConfigListeners that will be told about changes.
     */
    vector<sp<ConfigListener>> mListeners;

    /**
     * Call to load the saved configs from disk.
     */
    void readConfigFromDisk();
};

}  // namespace statsd