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

Commit adaf8b34 authored by David Chen's avatar David Chen
Browse files

Adds client API for interacting with statsd.

This API will primarily be used by GmsCore to send updated configs.
Also, sending a config will implicitly notify the StatsD that this
client wants to know when it should request data for this config.

We send a broadcast so that all interested subscribers can know if
data needs to be pulled.

Test: Manually tested that sending broadcast works via new adb
command added in StatsService.

Change-Id: I23cdd1df706036e14b32c3d01af30c3d4af819fa
parent 2dd2cbcb
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -9668,6 +9668,7 @@ package android.content {
    field public static final java.lang.String SEARCH_SERVICE = "search";
    field public static final java.lang.String SENSOR_SERVICE = "sensor";
    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
    field public static final java.lang.String STATS_MANAGER = "stats";
    field public static final java.lang.String STORAGE_SERVICE = "storage";
    field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
    field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
@@ -48167,6 +48168,12 @@ package android.util {
    field public static final int[] WILD_CARD;
  }
  public final class StatsManager {
    method public byte[] getData(java.lang.String);
    method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
    method public boolean removeConfiguration(java.lang.String);
  }
  public class StringBuilderPrinter implements android.util.Printer {
    ctor public StringBuilderPrinter(java.lang.StringBuilder);
    method public void println(java.lang.String);
+62 −19
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include "Log.h"

#include "StatsService.h"
#include "config/ConfigKey.h"
#include "config/ConfigManager.h"
#include "storage/DropboxReader.h"

#include <android-base/file.h>
@@ -39,6 +41,8 @@ namespace android {
namespace os {
namespace statsd {

constexpr const char* kPermissionDump = "android.permission.DUMP";

// ======================================================================
/**
 * Watches for the death of the stats companion (system process).
@@ -67,8 +71,8 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
{
    mUidMap = new UidMap();
    mConfigManager = new ConfigManager();
    mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) {
      pushLog(log);
    mProcessor = new StatsLogProcessor(mUidMap, [](const vector<uint8_t>& log) {
        // TODO: Update how we send data out of StatsD.
    });

    mConfigManager->AddListener(mProcessor);
@@ -198,6 +202,10 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
        if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
            return cmd_print_pulled_metrics(out, args);
        }

        if (!args[0].compare(String8("send-broadcast"))) {
            return cmd_trigger_broadcast(args);
        }
    }

    print_cmd_help(out);
@@ -238,6 +246,19 @@ void StatsService::print_cmd_help(FILE* out) {
    fprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
    fprintf(out, "                calling uid is used.\n");
    fprintf(out, "  NAME          The name of the configuration\n");
    fprintf(out, "\n");
    fprintf(out, "\n");
    fprintf(out, "usage: adb shell cmd stats send-broadcast PACKAGE CLASS\n");
    fprintf(out, "  Send a broadcast that triggers one subscriber to fetch metrics.\n");
    fprintf(out, "  PACKAGE        The name of the package to receive the broadcast.\n");
    fprintf(out, "  CLASS          The name of the class to receive the broadcast.\n");
}

status_t StatsService::cmd_trigger_broadcast(Vector<String8>& args) {
    auto sc = getStatsCompanionService();
    sc->sendBroadcast(String16(args[1]), String16(args[2]));
    ALOGD("StatsService::trigger broadcast succeeded");
    return NO_ERROR;
}

status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
@@ -520,29 +541,51 @@ void StatsService::OnLogEvent(const LogEvent& event) {
    mProcessor->OnLogEvent(event);
}

Status StatsService::requestPush() {
    mProcessor->flush();
Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
    IPCThreadState* ipc = IPCThreadState::self();
    if (checkCallingPermission(String16(kPermissionDump),
                               reinterpret_cast<int32_t*>(ipc->getCallingPid()),
                               reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
        // TODO: Implement this.
        return Status::ok();
}

Status StatsService::pushLog(const vector<uint8_t>& log) {
    std::lock_guard<std::mutex> lock(mLock);
    for (size_t i = 0; i < mCallbacks.size(); i++) {
        mCallbacks[i]->onReceiveLogs((vector<uint8_t>*)&log);
    }
    } else {
        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
    }
}

Status StatsService::addConfiguration(const String16& key,
                                      const vector <uint8_t>& config,
                                      const String16& package, const String16& cls,
                                      bool* success) {
    IPCThreadState* ipc = IPCThreadState::self();
    int32_t* uid = reinterpret_cast<int32_t*>(ipc->getCallingUid());
    if (checkCallingPermission(String16(kPermissionDump),
                               reinterpret_cast<int32_t*>(ipc->getCallingPid()), uid)) {
        string keyString = string(String8(key).string());
        ConfigKey configKey(*uid, keyString);
        StatsdConfig cfg;
        cfg.ParseFromArray(&config[0], config.size());
        mConfigManager->UpdateConfig(configKey, cfg);
        mConfigManager->SetConfigReceiver(configKey, string(String8(package).string()),
                                          string(String8(cls).string()));
        *success = true;
        return Status::ok();
}

Status StatsService::subscribeStatsLog(const sp<IStatsCallbacks>& callback) {
    std::lock_guard<std::mutex> lock(mLock);
    for (size_t i = 0; i < mCallbacks.size(); i++) {
        if (mCallbacks[i] == callback) {
           return Status::fromStatusT(-errno);
    } else {
        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
    }
}
    mCallbacks.add(callback);
    IInterface::asBinder(callback)->linkToDeath(this);

Status StatsService::removeConfiguration(const String16& key, bool* success) {
    IPCThreadState* ipc = IPCThreadState::self();
    if (checkCallingPermission(String16(kPermissionDump),
                               reinterpret_cast<int32_t*>(ipc->getCallingPid()),
                               reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
        // TODO: Implement this.
        return Status::ok();
    } else {
        *success = false;
        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
    }
}

void StatsService::binderDied(const wp<IBinder>& who) {
+14 −7
Original line number Diff line number Diff line
@@ -71,20 +71,22 @@ public:
    virtual void OnLogEvent(const LogEvent& event);

    /**
     * Binder call to force trigger pushLog. This would be called by callback
     * clients.
     * Binder call for clients to request data for this configuration key.
     */
    virtual Status requestPush() override;
    virtual Status getData(const String16& key, vector<uint8_t>* output) override;

    /**
     * Pushes stats log entries from statsd to callback clients.
     * Binder call to let clients send a configuration and indicate they're interested when they
     * should requestData for this configuration.
     */
    Status pushLog(const vector<uint8_t>& log);
    virtual Status addConfiguration(const String16& key, const vector <uint8_t>& config,
                                   const String16& package, const String16& cls, bool* success)
    override;

    /**
     * Binder call to listen to statsd to send stats log entries.
     * Binder call to allow clients to remove the specified configuration.
     */
    virtual Status subscribeStatsLog(const sp<IStatsCallbacks>& callbacks) override;
    virtual Status removeConfiguration(const String16& key, bool* success) override;

    // TODO: public for testing since statsd doesn't run when system starts. Change to private
    // later.
@@ -119,6 +121,11 @@ private:
     */
    void print_cmd_help(FILE* out);

    /**
     * Trigger a broadcast.
     */
    status_t cmd_trigger_broadcast(Vector<String8>& args);

    /**
     * Handle the config sub-command.
     */
+9 −0
Original line number Diff line number Diff line
@@ -60,6 +60,14 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
    }
}

void ConfigManager::SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls) {
    mConfigReceivers[key] = pair<string, string>(pkg, cls);
}

void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
    mConfigReceivers.erase(key);
}

void ConfigManager::RemoveConfig(const ConfigKey& key) {
    unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
    if (it != mConfigs.end()) {
@@ -85,6 +93,7 @@ void ConfigManager::RemoveConfigs(int uid) {
        if (it->first.GetUid() == uid) {
            removed.push_back(it->first);
            it = mConfigs.erase(it);
            mConfigReceivers.erase(it->first);
        } else {
            it++;
        }
+18 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ using android::RefBase;
using std::string;
using std::unordered_map;
using std::vector;
using std::pair;

/**
 * Keeps track of which configurations have been set from various sources.
@@ -63,6 +64,16 @@ public:
     */
    void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);

    /**
     * Sets the broadcast receiver for a configuration key.
     */
    void SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls);

    /**
     * Erase any broadcast receiver associated with this config key.
     */
    void RemoveConfigReceiver(const ConfigKey& key);

    /**
     * A configuration was removed.
     *
@@ -87,10 +98,16 @@ private:
    void update_saved_configs();

    /**
     * The Configs that have been set
     * The Configs that have been set. Each config should
     */
    unordered_map<ConfigKey, StatsdConfig> mConfigs;

    /**
     * Each config key can be subscribed by up to one receiver, specified as the package name and
     * class name.
     */
    unordered_map<ConfigKey, pair<string, string>> mConfigReceivers;

    /**
     * The ConfigListeners that will be told about changes.
     */
Loading