Add more alert details to incidentd header.
+ Add metric_id, dimension, metric_value in the incident report header to make it easier to identify an anomaly. + In case there is a uid in the dimension, put the its package info in the header too Test: statsd_test && tested locally with a config Change-Id: I762a1a4b0563fb3104e0d32b616b4a2367485e48
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "FieldValue.h"
|
||||
#include "HashableDimensionKey.h"
|
||||
#include "math.h"
|
||||
#include "statslog.h"
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
@@ -122,6 +123,24 @@ bool isAttributionUidField(const FieldValue& value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t getUidIfExists(const FieldValue& value) {
|
||||
bool isUid = false;
|
||||
// the field is uid field if the field is the uid field in attribution node or marked as
|
||||
// is_uid in atoms.proto
|
||||
if (isAttributionUidField(value)) {
|
||||
isUid = true;
|
||||
} else {
|
||||
auto it = android::util::AtomsInfo::kAtomsWithUidField.find(value.mField.getTag());
|
||||
if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
|
||||
int uidField = it->second; // uidField is the field number in proto
|
||||
isUid = value.mField.getDepth() == 0 && value.mField.getPosAtDepth(0) == uidField &&
|
||||
value.mValue.getType() == INT;
|
||||
}
|
||||
}
|
||||
|
||||
return isUid ? value.mValue.int_value : -1;
|
||||
}
|
||||
|
||||
bool isAttributionUidField(const Field& field, const Value& value) {
|
||||
int f = field.getField() & 0xff007f;
|
||||
if (f == 0x10001 && value.getType() == INT) {
|
||||
|
||||
@@ -386,6 +386,9 @@ bool HasPositionALL(const FieldMatcher& matcher);
|
||||
|
||||
bool isAttributionUidField(const FieldValue& value);
|
||||
|
||||
/* returns uid if the field is uid field, or -1 if the field is not a uid field */
|
||||
int getUidIfExists(const FieldValue& value);
|
||||
|
||||
void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
|
||||
|
||||
bool isAttributionUidField(const Field& field, const Value& value);
|
||||
|
||||
@@ -160,7 +160,7 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
|
||||
}
|
||||
|
||||
})) {
|
||||
mUidMap = new UidMap();
|
||||
mUidMap = UidMap::getInstance();
|
||||
mPullerManager = new StatsPullerManager();
|
||||
StatsPuller::SetUidMap(mUidMap);
|
||||
mConfigManager = new ConfigManager();
|
||||
|
||||
@@ -78,8 +78,8 @@ void AlarmTracker::informAlarmsFired(
|
||||
}
|
||||
if (!mSubscriptions.empty()) {
|
||||
VLOG("AlarmTracker triggers the subscribers.");
|
||||
triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
|
||||
mSubscriptions);
|
||||
triggerSubscribers(mAlarmConfig.id(), 0 /*metricId N/A*/, DEFAULT_METRIC_DIMENSION_KEY,
|
||||
0 /* metricValue N/A */, mConfigKey, mSubscriptions);
|
||||
}
|
||||
firedAlarms.erase(mInternalAlarm);
|
||||
mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
|
||||
|
||||
@@ -207,7 +207,8 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
|
||||
getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
|
||||
}
|
||||
|
||||
void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key) {
|
||||
void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, int64_t metricId,
|
||||
const MetricDimensionKey& key, int64_t metricValue) {
|
||||
// TODO(b/110563466): Why receive timestamp? RefractoryPeriod should always be based on
|
||||
// real time right now.
|
||||
if (isInRefractoryPeriod(timestampNs, key)) {
|
||||
@@ -225,7 +226,7 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime
|
||||
if (!mSubscriptions.empty()) {
|
||||
ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
|
||||
mAlert.id(), key.toString().c_str());
|
||||
informSubscribers(key);
|
||||
informSubscribers(key, metricId, metricValue);
|
||||
} else {
|
||||
ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
|
||||
}
|
||||
@@ -238,11 +239,11 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime
|
||||
}
|
||||
|
||||
void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
|
||||
const int64_t& currBucketNum,
|
||||
const int64_t& currBucketNum, int64_t metricId,
|
||||
const MetricDimensionKey& key,
|
||||
const int64_t& currentBucketValue) {
|
||||
if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
|
||||
declareAnomaly(timestampNs, key);
|
||||
declareAnomaly(timestampNs, metricId, key, currentBucketValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +256,9 @@ bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs,
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
|
||||
triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions);
|
||||
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id,
|
||||
int64_t metricValue) {
|
||||
triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -67,14 +67,16 @@ public:
|
||||
const int64_t& currentBucketValue);
|
||||
|
||||
// Informs incidentd about the detected alert.
|
||||
void declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key);
|
||||
void declareAnomaly(const int64_t& timestampNs, int64_t metricId, const MetricDimensionKey& key,
|
||||
int64_t metricValue);
|
||||
|
||||
// Detects if, based on past buckets plus the new currentBucketValue (which generally
|
||||
// represents the partially-filled current bucket), an anomaly has happened, and if so,
|
||||
// declares an anomaly and informs relevant subscribers.
|
||||
// Also advances to currBucketNum-1.
|
||||
void detectAndDeclareAnomaly(const int64_t& timestampNs, const int64_t& currBucketNum,
|
||||
const MetricDimensionKey& key, const int64_t& currentBucketValue);
|
||||
int64_t metricId, const MetricDimensionKey& key,
|
||||
const int64_t& currentBucketValue);
|
||||
|
||||
// Init the AlarmMonitor which is shared across anomaly trackers.
|
||||
virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) {
|
||||
@@ -176,7 +178,7 @@ protected:
|
||||
virtual void resetStorage();
|
||||
|
||||
// Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred.
|
||||
void informSubscribers(const MetricDimensionKey& key);
|
||||
void informSubscribers(const MetricDimensionKey& key, int64_t metricId, int64_t metricValue);
|
||||
|
||||
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
|
||||
FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
|
||||
|
||||
@@ -65,7 +65,9 @@ void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey,
|
||||
|
||||
// If the alarm is set in the past but hasn't fired yet (due to lag), catch it now.
|
||||
if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) {
|
||||
declareAnomaly(timestampNs, dimensionKey);
|
||||
declareAnomaly(timestampNs, mAlert.metric_id(), dimensionKey,
|
||||
mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) -
|
||||
itr->second->timestampSec);
|
||||
}
|
||||
if (mAlarmMonitor != nullptr) {
|
||||
mAlarmMonitor->remove(itr->second);
|
||||
@@ -100,7 +102,9 @@ void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs,
|
||||
|
||||
// Now declare each of these alarms to have fired.
|
||||
for (const auto& kv : matchedAlarms) {
|
||||
declareAnomaly(timestampNs, kv.first);
|
||||
declareAnomaly(
|
||||
timestampNs, mAlert.metric_id(), kv.first,
|
||||
mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - kv.second->timestampSec);
|
||||
mAlarms.erase(kv.first);
|
||||
firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it.
|
||||
}
|
||||
|
||||
@@ -30,9 +30,8 @@ namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
void triggerSubscribers(const int64_t rule_id,
|
||||
const MetricDimensionKey& dimensionKey,
|
||||
const ConfigKey& configKey,
|
||||
void triggerSubscribers(int64_t ruleId, int64_t metricId, const MetricDimensionKey& dimensionKey,
|
||||
int64_t metricValue, const ConfigKey& configKey,
|
||||
const std::vector<Subscription>& subscriptions) {
|
||||
VLOG("informSubscribers called.");
|
||||
if (subscriptions.empty()) {
|
||||
@@ -50,13 +49,14 @@ void triggerSubscribers(const int64_t rule_id,
|
||||
}
|
||||
switch (subscription.subscriber_information_case()) {
|
||||
case Subscription::SubscriberInformationCase::kIncidentdDetails:
|
||||
if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) {
|
||||
if (!GenerateIncidentReport(subscription.incidentd_details(), ruleId, metricId,
|
||||
dimensionKey, metricValue, configKey)) {
|
||||
ALOGW("Failed to generate incident report.");
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kPerfettoDetails:
|
||||
if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
|
||||
subscription.id(), rule_id, configKey)) {
|
||||
subscription.id(), ruleId, configKey)) {
|
||||
ALOGW("Failed to generate perfetto traces.");
|
||||
}
|
||||
break;
|
||||
@@ -66,7 +66,7 @@ void triggerSubscribers(const int64_t rule_id,
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kPerfprofdDetails:
|
||||
if (!CollectPerfprofdTraceAndUploadToDropbox(subscription.perfprofd_details(),
|
||||
rule_id, configKey)) {
|
||||
ruleId, configKey)) {
|
||||
ALOGW("Failed to generate perfprofd traces.");
|
||||
}
|
||||
break;
|
||||
@@ -76,7 +76,6 @@ void triggerSubscribers(const int64_t rule_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
@@ -24,10 +24,9 @@ namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
void triggerSubscribers(const int64_t rule_id,
|
||||
const MetricDimensionKey& dimensionKey,
|
||||
const ConfigKey& configKey,
|
||||
const std::vector<Subscription>& subscriptions);
|
||||
void triggerSubscribers(const int64_t ruleId, const int64_t metricId,
|
||||
const MetricDimensionKey& dimensionKey, int64_t metricValue,
|
||||
const ConfigKey& configKey, const std::vector<Subscription>& subscriptions);
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
|
||||
@@ -303,7 +303,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked(
|
||||
if (prev != mCurrentFullCounters->end()) {
|
||||
countWholeBucket += prev->second;
|
||||
}
|
||||
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
|
||||
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
|
||||
countWholeBucket);
|
||||
}
|
||||
|
||||
|
||||
@@ -485,8 +485,8 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
|
||||
gaugeVal = value.long_value;
|
||||
}
|
||||
for (auto& tracker : mAnomalyTrackers) {
|
||||
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
|
||||
gaugeVal);
|
||||
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId,
|
||||
eventKey, gaugeVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,8 +693,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
|
||||
wholeBucketVal += prev->second;
|
||||
}
|
||||
for (auto& tracker : mAnomalyTrackers) {
|
||||
tracker->detectAndDeclareAnomaly(
|
||||
eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
|
||||
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
|
||||
wholeBucketVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,8 @@ protected:
|
||||
const int64_t& currentBucketValue) {
|
||||
for (auto& anomalyTracker : mAnomalyTrackers) {
|
||||
if (anomalyTracker != nullptr) {
|
||||
anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mEventKey,
|
||||
currentBucketValue);
|
||||
anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId,
|
||||
mEventKey, currentBucketValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ UidMap::UidMap() : mBytesUsed(0) {}
|
||||
|
||||
UidMap::~UidMap() {}
|
||||
|
||||
sp<UidMap> UidMap::getInstance() {
|
||||
static sp<UidMap> sInstance = new UidMap();
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
bool UidMap::hasApp(int uid, const string& packageName) const {
|
||||
lock_guard<mutex> lock(mMutex);
|
||||
|
||||
@@ -336,6 +341,61 @@ size_t UidMap::getBytesUsed() const {
|
||||
return mBytesUsed;
|
||||
}
|
||||
|
||||
void UidMap::writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings,
|
||||
bool includeInstaller, const std::set<int32_t>& interestingUids,
|
||||
std::set<string>* str_set, ProtoOutputStream* proto) {
|
||||
lock_guard<mutex> lock(mMutex);
|
||||
|
||||
writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller, interestingUids,
|
||||
str_set, proto);
|
||||
}
|
||||
|
||||
void UidMap::writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
|
||||
bool includeInstaller,
|
||||
const std::set<int32_t>& interestingUids,
|
||||
std::set<string>* str_set, ProtoOutputStream* proto) {
|
||||
proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
|
||||
for (const auto& kv : mMap) {
|
||||
if (!interestingUids.empty() &&
|
||||
interestingUids.find(kv.first.first) == interestingUids.end()) {
|
||||
continue;
|
||||
}
|
||||
uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
|
||||
FIELD_ID_SNAPSHOT_PACKAGE_INFO);
|
||||
if (str_set != nullptr) {
|
||||
str_set->insert(kv.first.second);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
|
||||
(long long)Hash64(kv.first.second));
|
||||
if (includeVersionStrings) {
|
||||
str_set->insert(kv.second.versionString);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH,
|
||||
(long long)Hash64(kv.second.versionString));
|
||||
}
|
||||
if (includeInstaller) {
|
||||
str_set->insert(kv.second.installer);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH,
|
||||
(long long)Hash64(kv.second.installer));
|
||||
}
|
||||
} else {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
|
||||
if (includeVersionStrings) {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING,
|
||||
kv.second.versionString);
|
||||
}
|
||||
if (includeInstaller) {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER,
|
||||
kv.second.installer);
|
||||
}
|
||||
}
|
||||
|
||||
proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
|
||||
(long long)kv.second.versionCode);
|
||||
proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
|
||||
proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
|
||||
proto->end(token);
|
||||
}
|
||||
}
|
||||
|
||||
void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
|
||||
bool includeVersionStrings, bool includeInstaller,
|
||||
ProtoOutputStream* proto) {
|
||||
@@ -381,43 +441,9 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::s
|
||||
// Write snapshot from current uid map state.
|
||||
uint64_t snapshotsToken =
|
||||
proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
|
||||
proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
|
||||
for (const auto& kv : mMap) {
|
||||
uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
|
||||
FIELD_ID_SNAPSHOT_PACKAGE_INFO);
|
||||
|
||||
if (str_set != nullptr) {
|
||||
str_set->insert(kv.first.second);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
|
||||
(long long)Hash64(kv.first.second));
|
||||
if (includeVersionStrings) {
|
||||
str_set->insert(kv.second.versionString);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH,
|
||||
(long long)Hash64(kv.second.versionString));
|
||||
}
|
||||
if (includeInstaller) {
|
||||
str_set->insert(kv.second.installer);
|
||||
proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH,
|
||||
(long long)Hash64(kv.second.installer));
|
||||
}
|
||||
} else {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
|
||||
if (includeVersionStrings) {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING,
|
||||
kv.second.versionString);
|
||||
}
|
||||
if (includeInstaller) {
|
||||
proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER,
|
||||
kv.second.installer);
|
||||
}
|
||||
}
|
||||
|
||||
proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
|
||||
(long long)kv.second.versionCode);
|
||||
proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
|
||||
proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
|
||||
proto->end(token);
|
||||
}
|
||||
writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller,
|
||||
std::set<int32_t>() /*empty uid set means including every uid*/,
|
||||
str_set, proto);
|
||||
proto->end(snapshotsToken);
|
||||
|
||||
int64_t prevMin = getMinimumTimestampNs();
|
||||
|
||||
@@ -91,6 +91,8 @@ public:
|
||||
UidMap();
|
||||
~UidMap();
|
||||
static const std::map<std::string, uint32_t> sAidToUidMapping;
|
||||
|
||||
static sp<UidMap> getInstance();
|
||||
/*
|
||||
* All three inputs must be the same size, and the jth element in each array refers to the same
|
||||
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
|
||||
@@ -152,12 +154,25 @@ public:
|
||||
|
||||
std::set<int32_t> getAppUid(const string& package) const;
|
||||
|
||||
// Write current PackageInfoSnapshot to ProtoOutputStream.
|
||||
// interestingUids: If not empty, only write the package info for these uids. If empty, write
|
||||
// package info for all uids.
|
||||
// str_set: if not null, add new string to the set and write str_hash to proto
|
||||
// if null, write string to proto.
|
||||
void writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings, bool includeInstaller,
|
||||
const std::set<int32_t>& interestingUids, std::set<string>* str_set,
|
||||
ProtoOutputStream* proto);
|
||||
|
||||
private:
|
||||
std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
|
||||
string normalizeAppName(const string& appName) const;
|
||||
|
||||
void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
|
||||
|
||||
void writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
|
||||
bool includeInstaller, const std::set<int32_t>& interestingUids,
|
||||
std::set<string>* str_set, ProtoOutputStream* proto);
|
||||
|
||||
mutable mutex mMutex;
|
||||
mutable mutex mIsolatedMutex;
|
||||
|
||||
|
||||
@@ -456,3 +456,17 @@ message StatsdStatsReport {
|
||||
}
|
||||
repeated LogLossStats detected_log_loss = 16;
|
||||
}
|
||||
|
||||
message AlertTriggerDetails {
|
||||
message MetricValue {
|
||||
optional int64 metric_id = 1;
|
||||
optional DimensionsValue dimension_in_what = 2;
|
||||
optional DimensionsValue dimension_in_condition = 3;
|
||||
optional int64 value = 4;
|
||||
}
|
||||
oneof value {
|
||||
MetricValue trigger_metric = 1;
|
||||
EventMetricData trigger_event = 2;
|
||||
}
|
||||
optional UidMapping.PackageInfoSnapshot package_info = 3;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
#define DEBUG false
|
||||
#include "Log.h"
|
||||
|
||||
#include "FieldValue.h"
|
||||
#include "IncidentdReporter.h"
|
||||
#include "packages/UidMap.h"
|
||||
#include "stats_log_util.h"
|
||||
|
||||
#include <android/os/IIncidentManager.h>
|
||||
#include <android/os/IncidentReportArgs.h>
|
||||
@@ -43,8 +46,18 @@ const int FIELD_ID_CONFIG_KEY = 3;
|
||||
const int FIELD_ID_CONFIG_KEY_UID = 1;
|
||||
const int FIELD_ID_CONFIG_KEY_ID = 2;
|
||||
|
||||
const int FIELD_ID_TRIGGER_DETAILS = 4;
|
||||
const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
|
||||
const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
|
||||
const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
|
||||
const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3;
|
||||
const int FIELD_ID_METRIC_VALUE_VALUE = 4;
|
||||
|
||||
const int FIELD_ID_PACKAGE_INFO = 3;
|
||||
|
||||
namespace {
|
||||
void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uint8_t>* protoData) {
|
||||
void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
|
||||
int64_t metricValue, const ConfigKey& configKey, vector<uint8_t>* protoData) {
|
||||
ProtoOutputStream headerProto;
|
||||
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
|
||||
uint64_t token =
|
||||
@@ -53,6 +66,58 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin
|
||||
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
|
||||
headerProto.end(token);
|
||||
|
||||
token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS);
|
||||
|
||||
// MetricValue trigger_metric = 1;
|
||||
uint64_t metricToken =
|
||||
headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC);
|
||||
// message MetricValue {
|
||||
// optional int64 metric_id = 1;
|
||||
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId);
|
||||
// optional DimensionsValue dimension_in_what = 2;
|
||||
uint64_t dimToken =
|
||||
headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT);
|
||||
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
|
||||
headerProto.end(dimToken);
|
||||
|
||||
// optional DimensionsValue dimension_in_condition = 3;
|
||||
dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION);
|
||||
writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto);
|
||||
headerProto.end(dimToken);
|
||||
|
||||
// optional int64 value = 4;
|
||||
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
|
||||
|
||||
// }
|
||||
headerProto.end(metricToken);
|
||||
|
||||
// write relevant uid package info
|
||||
std::set<int32_t> uids;
|
||||
|
||||
for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
|
||||
int uid = getUidIfExists(dim);
|
||||
// any uid <= 2000 are predefined AID_*
|
||||
if (uid > 2000) {
|
||||
uids.insert(uid);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) {
|
||||
int uid = getUidIfExists(dim);
|
||||
if (uid > 2000) {
|
||||
uids.insert(uid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uids.empty()) {
|
||||
uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
|
||||
UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
|
||||
nullptr /*string set*/, &headerProto);
|
||||
headerProto.end(token);
|
||||
}
|
||||
|
||||
headerProto.end(token);
|
||||
|
||||
protoData->resize(headerProto.size());
|
||||
size_t pos = 0;
|
||||
auto iter = headerProto.data();
|
||||
@@ -65,7 +130,8 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
|
||||
const MetricDimensionKey& dimensionKey, int64_t metricValue,
|
||||
const ConfigKey& configKey) {
|
||||
if (config.section_size() == 0) {
|
||||
VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
|
||||
@@ -76,7 +142,7 @@ bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_
|
||||
IncidentReportArgs incidentReport;
|
||||
|
||||
vector<uint8_t> protoData;
|
||||
getProtoData(rule_id, configKey, &protoData);
|
||||
getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey, &protoData);
|
||||
incidentReport.addHeader(protoData);
|
||||
|
||||
for (int i = 0; i < config.section_size(); i++) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HashableDimensionKey.h"
|
||||
#include "config/ConfigKey.h"
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert, IncidentdDetails
|
||||
|
||||
@@ -26,7 +27,8 @@ namespace statsd {
|
||||
/**
|
||||
* Calls incidentd to trigger an incident report and put in dropbox for uploading.
|
||||
*/
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
|
||||
const MetricDimensionKey& dimensionKey, int64_t metricValue,
|
||||
const ConfigKey& configKey);
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -90,7 +90,8 @@ void detectAndDeclareAnomalies(AnomalyTracker& tracker,
|
||||
const std::shared_ptr<DimToValMap>& bucket,
|
||||
const int64_t& eventTimestamp) {
|
||||
for (const auto& kv : *bucket) {
|
||||
tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second);
|
||||
tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, 0 /*metric_id*/, kv.first,
|
||||
kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,9 @@ message IncidentHeaderProto {
|
||||
optional int64 id = 2; // The unique id of the statsd config.
|
||||
}
|
||||
optional StatsdConfigKey config_key = 3;
|
||||
|
||||
// Details about the trigger. com.android.os.AlertTriggerDetails
|
||||
// Only use bytes type here to avoid indirect dependency on atoms.proto
|
||||
// And this header passes through incidentd without incidentd parsing it.
|
||||
optional bytes trigger_details = 4;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user