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
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 11c5de1..07b1c5c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -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 os {
namespace statsd {
+constexpr const char* kPermissionDump = "android.permission.DUMP";
+
// ======================================================================
/**
* Watches for the death of the stats companion (system process).
@@ -67,8 +71,8 @@
{
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 @@
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 @@
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 @@
mProcessor->OnLogEvent(event);
}
-Status StatsService::requestPush() {
- mProcessor->flush();
- return Status::ok();
+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();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+ }
}
-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);
+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();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
- 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);
- }
+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);
}
- mCallbacks.add(callback);
- IInterface::asBinder(callback)->linkToDeath(this);
- return Status::ok();
}
void StatsService::binderDied(const wp<IBinder>& who) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 1d7e5a61..7991d82 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -71,20 +71,22 @@
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.
@@ -120,6 +122,11 @@
void print_cmd_help(FILE* out);
/**
+ * Trigger a broadcast.
+ */
+ status_t cmd_trigger_broadcast(Vector<String8>& args);
+
+ /**
* Handle the config sub-command.
*/
status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index d86ab57..2a8a741 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -60,6 +60,14 @@
}
}
+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 @@
if (it->first.GetUid() == uid) {
removed.push_back(it->first);
it = mConfigs.erase(it);
+ mConfigReceivers.erase(it->first);
} else {
it++;
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 5d73eaf..c21247f9 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -32,6 +32,7 @@
using std::string;
using std::unordered_map;
using std::vector;
+using std::pair;
/**
* Keeps track of which configurations have been set from various sources.
@@ -64,6 +65,16 @@
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.
*
* Reports this to listeners.
@@ -87,11 +98,17 @@
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.
*/
vector<sp<ConfigListener>> mListeners;