summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/StatsService.cpp50
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp89
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp37
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h6
-rw-r--r--cmds/statsd/src/statsd_config.proto2
6 files changed, 144 insertions, 45 deletions
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4e4145439e25..32da94f862c5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -34,6 +34,7 @@
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
#include <utils/String16.h>
+#include <statslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -235,6 +236,10 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
if (!args[0].compare(String8("write-to-disk"))) {
return cmd_write_data_to_disk(out);
}
+
+ if (!args[0].compare(String8("log-app-hook"))) {
+ return cmd_log_app_hook(out, args);
+ }
}
print_cmd_help(out);
@@ -272,6 +277,15 @@ void StatsService::print_cmd_help(FILE* out) {
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
+ fprintf(out, " Writes an AppHook event to the statslog buffer.\n");
+ fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
+ fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ fprintf(out, " uid is used.\n");
+ fprintf(out, " LABEL Integer in [0, 15], as per atoms.proto.\n");
+ fprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
fprintf(out, "\n");
@@ -523,6 +537,42 @@ status_t StatsService::cmd_write_data_to_disk(FILE* out) {
return NO_ERROR;
}
+status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+ bool good = false;
+ int32_t uid;
+ int32_t label;
+ int32_t state;
+ const int argCount = args.size();
+ if (argCount == 3) {
+ // Automatically pick the UID
+ uid = IPCThreadState::self()->getCallingUid();
+ label = atoi(args[1].c_str());
+ state = atoi(args[2].c_str());
+ good = true;
+ } else if (argCount == 4) {
+ uid = atoi(args[1].c_str());
+ // If it's a userdebug or eng build, then the shell user can impersonate other uids.
+ // Otherwise, the uid must match the actual caller's uid.
+ if (mEngBuild || (uid >= 0 && (uid_t)uid == IPCThreadState::self()->getCallingUid())) {
+ label = atoi(args[2].c_str());
+ state = atoi(args[3].c_str());
+ good = true;
+ } else {
+ fprintf(out,
+ "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
+ " or userdebug builds.\n");
+ }
+ }
+ if (good) {
+ fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
+ android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+ } else {
+ print_cmd_help(out);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
vector<shared_ptr<LogEvent> > stats;
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fd3ed1dbed72..109752b0295f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -183,6 +183,11 @@ private:
status_t cmd_write_data_to_disk(FILE* out);
/**
+ * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+ */
+ status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+
+ /**
* Print contents of a pulled metrics source.
*/
status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index b6f440f2e348..fae91729fe4f 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -129,43 +129,60 @@ bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap
}
bool matched = false;
switch (matcher.value_matcher_case()) {
- case FieldValueMatcher::ValueMatcherCase::kEqBool:
- // Logd does not support bool, it is int instead.
- matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
- break;
- case FieldValueMatcher::ValueMatcherCase::kEqString:
- {
- if (IsAttributionUidField(*rootField)) {
- const int uid = ret.first->second.value_int();
- std::set<string> packageNames =
+ case FieldValueMatcher::ValueMatcherCase::kEqBool: {
+ // Logd does not support bool, it is int instead.
+ matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqString: {
+ if (IsAttributionUidField(*rootField)) {
+ const int uid = ret.first->second.value_int();
+ std::set<string> packageNames =
uidMap.getAppNamesFromUid(uid, true /* normalize*/);
- matched = packageNames.find(matcher.eq_string()) != packageNames.end();
- } else {
- matched = (ret.first->second.value_str() == matcher.eq_string());
- }
- }
- break;
- case FieldValueMatcher::ValueMatcherCase::kEqInt:
- matched = (ret.first->second.value_int() == matcher.eq_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLtInt:
- matched = (ret.first->second.value_int() < matcher.lt_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGtInt:
- matched = (ret.first->second.value_int() > matcher.gt_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLtFloat:
- matched = (ret.first->second.value_float() < matcher.lt_float());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGtFloat:
- matched = (ret.first->second.value_float() > matcher.gt_float());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLteInt:
- matched = (ret.first->second.value_int() <= matcher.lte_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGteInt:
- matched = (ret.first->second.value_int() >= matcher.gte_int());
- break;
+ matched = packageNames.find(matcher.eq_string()) != packageNames.end();
+ } else {
+ matched = (ret.first->second.value_str() == matcher.eq_string());
+ }
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val == matcher.eq_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val < matcher.lt_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val > matcher.gt_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
+ matched = (ret.first->second.value_float() < matcher.lt_float());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
+ matched = (ret.first->second.value_float() > matcher.gt_float());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLteInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val <= matcher.lte_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGteInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val >= matcher.gte_int());
+ break;
+ }
default:
break;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 636289522780..417145c00e54 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -47,7 +47,7 @@ const int FIELD_ID_METRICS = 1;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const long timeBaseSec, sp<UidMap> uidMap)
- : mConfigKey(key), mUidMap(uidMap) {
+ : mConfigKey(key), mUidMap(uidMap), mStatsdUid(getStatsdUid()) {
mConfigValid =
initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
@@ -61,6 +61,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mAllowedUid.push_back(1000);
mAllowedUid.push_back(0);
+ mAllowedUid.push_back(mStatsdUid);
mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
} else {
for (const auto& source : config.allowed_log_source()) {
@@ -191,18 +192,28 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
// TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+ status_t err = NO_ERROR;
+
+ // Uid is 3rd from last field and must match the caller's uid,
+ // unless that caller is statsd itself (statsd is allowed to spoof uids).
+ long appHookUid = event.GetLong(event.size()-2, &err);
+ int32_t loggerUid = event.GetUid();
+ if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != mStatsdUid)) {
+ VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid);
+ return;
+ }
// Label is 2nd from last field and must be from [0, 15].
- status_t err = NO_ERROR;
- long label = event.GetLong(event.size()-1, &err);
- if (err != NO_ERROR || label < 0 || label > 15) {
- VLOG("App hook does not have valid label %ld", label);
+ long appHookLabel = event.GetLong(event.size()-1, &err);
+ if (err != NO_ERROR || appHookLabel < 0 || appHookLabel > 15) {
+ VLOG("AppHook does not have valid label %ld", appHookLabel);
return;
}
+
// The state must be from 0,3. This part of code must be manually updated.
- long apphookState = event.GetLong(event.size(), &err);
- if (err != NO_ERROR || apphookState < 0 || apphookState > 3) {
- VLOG("App hook does not have valid state %ld", apphookState);
+ long appHookState = event.GetLong(event.size(), &err);
+ if (err != NO_ERROR || appHookState < 0 || appHookState > 3) {
+ VLOG("AppHook does not have valid state %ld", appHookState);
return;
}
} else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
@@ -322,6 +333,16 @@ size_t MetricsManager::byteSize() {
return totalSize;
}
+int32_t MetricsManager::getStatsdUid() {
+ auto suit = UidMap::sAidToUidMapping.find("AID_STATSD");
+ if (suit != UidMap::sAidToUidMapping.end()) {
+ return suit->second;
+ } else {
+ ALOGE("Statsd failed to find its own uid!");
+ return -1;
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d4b9102d5ddc..a1220f9ecd49 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -75,6 +75,9 @@ private:
sp<UidMap> mUidMap;
+ // The uid of statsd.
+ const int32_t mStatsdUid;
+
bool mConfigValid = false;
// The uid log sources from StatsdConfig.
@@ -136,6 +139,9 @@ private:
void initLogSourceWhiteList();
+ // Fetches the uid of statsd from UidMap.
+ static int32_t getStatsdUid();
+
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 2ea79a64a5ea..3eaf7a17a3e2 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -64,7 +64,7 @@ message FieldValueMatcher {
oneof value_matcher {
bool eq_bool = 3;
string eq_string = 4;
- int32 eq_int = 5;
+ int64 eq_int = 5;
int64 lt_int = 6;
int64 gt_int = 7;