Loading cmds/statsd/src/StatsService.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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; Loading cmds/statsd/src/StatsService.h +5 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,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. */ Loading cmds/statsd/src/matchers/matcher_util.cpp +53 −36 Original line number Diff line number Diff line Loading @@ -129,12 +129,12 @@ bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap } bool matched = false; switch (matcher.value_matcher_case()) { case FieldValueMatcher::ValueMatcherCase::kEqBool: 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: { } case FieldValueMatcher::ValueMatcherCase::kEqString: { if (IsAttributionUidField(*rootField)) { const int uid = ret.first->second.value_int(); std::set<string> packageNames = Loading @@ -143,29 +143,46 @@ bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap } else { matched = (ret.first->second.value_str() == matcher.eq_string()); } } break; case FieldValueMatcher::ValueMatcherCase::kEqInt: matched = (ret.first->second.value_int() == matcher.eq_int()); } 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: matched = (ret.first->second.value_int() < matcher.lt_int()); } 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: matched = (ret.first->second.value_int() > matcher.gt_int()); } 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: } case FieldValueMatcher::ValueMatcherCase::kLtFloat: { matched = (ret.first->second.value_float() < matcher.lt_float()); break; case FieldValueMatcher::ValueMatcherCase::kGtFloat: } 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()); } 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: matched = (ret.first->second.value_int() >= matcher.gte_int()); } 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; } Loading cmds/statsd/src/metrics/MetricsManager.cpp +29 −8 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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()) { Loading Loading @@ -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) { Loading Loading @@ -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 cmds/statsd/src/metrics/MetricsManager.h +6 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading Loading
cmds/statsd/src/StatsService.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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; Loading
cmds/statsd/src/StatsService.h +5 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,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. */ Loading
cmds/statsd/src/matchers/matcher_util.cpp +53 −36 Original line number Diff line number Diff line Loading @@ -129,12 +129,12 @@ bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap } bool matched = false; switch (matcher.value_matcher_case()) { case FieldValueMatcher::ValueMatcherCase::kEqBool: 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: { } case FieldValueMatcher::ValueMatcherCase::kEqString: { if (IsAttributionUidField(*rootField)) { const int uid = ret.first->second.value_int(); std::set<string> packageNames = Loading @@ -143,29 +143,46 @@ bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap } else { matched = (ret.first->second.value_str() == matcher.eq_string()); } } break; case FieldValueMatcher::ValueMatcherCase::kEqInt: matched = (ret.first->second.value_int() == matcher.eq_int()); } 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: matched = (ret.first->second.value_int() < matcher.lt_int()); } 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: matched = (ret.first->second.value_int() > matcher.gt_int()); } 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: } case FieldValueMatcher::ValueMatcherCase::kLtFloat: { matched = (ret.first->second.value_float() < matcher.lt_float()); break; case FieldValueMatcher::ValueMatcherCase::kGtFloat: } 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()); } 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: matched = (ret.first->second.value_int() >= matcher.gte_int()); } 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; } Loading
cmds/statsd/src/metrics/MetricsManager.cpp +29 −8 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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()) { Loading Loading @@ -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) { Loading Loading @@ -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
cmds/statsd/src/metrics/MetricsManager.h +6 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading