diff options
| -rw-r--r-- | cmds/statsd/src/StatsService.cpp | 50 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.h | 5 | ||||
| -rw-r--r-- | cmds/statsd/src/matchers/matcher_util.cpp | 89 | ||||
| -rw-r--r-- | cmds/statsd/src/metrics/MetricsManager.cpp | 37 | ||||
| -rw-r--r-- | cmds/statsd/src/metrics/MetricsManager.h | 6 | ||||
| -rw-r--r-- | cmds/statsd/src/statsd_config.proto | 2 |
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; |