Merge "Alarm: wakes up statsd and notifies the subscribers."
This commit is contained in:
committed by
Android (Google) Code Review
commit
03b91d77c4
@ -21,9 +21,11 @@ statsd_common_src := \
|
||||
src/statsd_config.proto \
|
||||
src/FieldValue.cpp \
|
||||
src/stats_log_util.cpp \
|
||||
src/anomaly/AnomalyMonitor.cpp \
|
||||
src/anomaly/AlarmMonitor.cpp \
|
||||
src/anomaly/AlarmTracker.cpp \
|
||||
src/anomaly/AnomalyTracker.cpp \
|
||||
src/anomaly/DurationAnomalyTracker.cpp \
|
||||
src/anomaly/subscriber_util.cpp \
|
||||
src/condition/CombinationConditionTracker.cpp \
|
||||
src/condition/condition_util.cpp \
|
||||
src/condition/SimpleConditionTracker.cpp \
|
||||
@ -172,7 +174,8 @@ LOCAL_SRC_FILES := \
|
||||
src/atom_field_options.proto \
|
||||
src/atoms.proto \
|
||||
src/stats_log.proto \
|
||||
tests/AnomalyMonitor_test.cpp \
|
||||
tests/AlarmMonitor_test.cpp \
|
||||
tests/anomaly/AlarmTracker_test.cpp \
|
||||
tests/anomaly/AnomalyTracker_test.cpp \
|
||||
tests/ConfigManager_test.cpp \
|
||||
tests/external/puller_util_test.cpp \
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
mValues = values;
|
||||
}
|
||||
|
||||
HashableDimensionKey(){};
|
||||
HashableDimensionKey() {};
|
||||
|
||||
HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
|
||||
|
||||
|
@ -66,11 +66,13 @@ const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
|
||||
#define STATS_DATA_DIR "/data/misc/stats-data"
|
||||
|
||||
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
|
||||
const sp<AnomalyMonitor>& anomalyMonitor,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor,
|
||||
const long timeBaseSec,
|
||||
const std::function<void(const ConfigKey&)>& sendBroadcast)
|
||||
: mUidMap(uidMap),
|
||||
mAnomalyMonitor(anomalyMonitor),
|
||||
mAnomalyAlarmMonitor(anomalyAlarmMonitor),
|
||||
mPeriodicAlarmMonitor(periodicAlarmMonitor),
|
||||
mSendBroadcast(sendBroadcast),
|
||||
mTimeBaseSec(timeBaseSec) {
|
||||
StatsPullerManager statsPullerManager;
|
||||
@ -82,10 +84,19 @@ StatsLogProcessor::~StatsLogProcessor() {
|
||||
|
||||
void StatsLogProcessor::onAnomalyAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) {
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
|
||||
std::lock_guard<std::mutex> lock(mMetricsMutex);
|
||||
for (const auto& itr : mMetricsManagers) {
|
||||
itr.second->onAnomalyAlarmFired(timestampNs, anomalySet);
|
||||
itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
|
||||
}
|
||||
}
|
||||
void StatsLogProcessor::onPeriodicAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(mMetricsMutex);
|
||||
for (const auto& itr : mMetricsManagers) {
|
||||
itr.second->onPeriodicAlarmFired(timestampNs, alarmSet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +181,9 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
|
||||
void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
|
||||
std::lock_guard<std::mutex> lock(mMetricsMutex);
|
||||
VLOG("Updated configuration for key %s", key.ToString().c_str());
|
||||
sp<MetricsManager> newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap);
|
||||
sp<MetricsManager> newMetricsManager =
|
||||
new MetricsManager(key, config, mTimeBaseSec, mUidMap,
|
||||
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
|
||||
auto it = mMetricsManagers.find(key);
|
||||
if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
|
||||
ALOGE("Can't accept more configs!");
|
||||
@ -179,7 +192,6 @@ void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig
|
||||
|
||||
if (newMetricsManager->isConfigValid()) {
|
||||
mUidMap->OnConfigUpdated(key);
|
||||
newMetricsManager->setAnomalyMonitor(mAnomalyMonitor);
|
||||
if (newMetricsManager->shouldAddUidMapListener()) {
|
||||
// We have to add listener after the MetricsManager is constructed because it's
|
||||
// not safe to create wp or sp from this pointer inside its constructor.
|
||||
|
@ -34,7 +34,8 @@ namespace statsd {
|
||||
|
||||
class StatsLogProcessor : public ConfigListener {
|
||||
public:
|
||||
StatsLogProcessor(const sp<UidMap>& uidMap, const sp<AnomalyMonitor>& anomalyMonitor,
|
||||
StatsLogProcessor(const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
|
||||
const long timeBaseSec,
|
||||
const std::function<void(const ConfigKey&)>& sendBroadcast);
|
||||
virtual ~StatsLogProcessor();
|
||||
@ -48,10 +49,15 @@ public:
|
||||
|
||||
void onDumpReport(const ConfigKey& key, const uint64_t dumpTimeNs, vector<uint8_t>* outData);
|
||||
|
||||
/* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
|
||||
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
|
||||
void onAnomalyAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet);
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
|
||||
|
||||
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
|
||||
void onPeriodicAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
|
||||
|
||||
/* Flushes data to disk. Data on memory will be gone after written to disk. */
|
||||
void WriteDataToDisk();
|
||||
@ -76,7 +82,9 @@ private:
|
||||
|
||||
StatsPullerManager mStatsPullerManager;
|
||||
|
||||
sp<AnomalyMonitor> mAnomalyMonitor;
|
||||
sp<AlarmMonitor> mAnomalyAlarmMonitor;
|
||||
|
||||
sp<AlarmMonitor> mPeriodicAlarmMonitor;
|
||||
|
||||
void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs,
|
||||
vector<uint8_t>* outData);
|
||||
|
@ -50,49 +50,73 @@ namespace statsd {
|
||||
constexpr const char* kPermissionDump = "android.permission.DUMP";
|
||||
#define STATS_SERVICE_DIR "/data/misc/stats-service"
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* Watches for the death of the stats companion (system process).
|
||||
*/
|
||||
class CompanionDeathRecipient : public IBinder::DeathRecipient {
|
||||
public:
|
||||
CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor);
|
||||
CompanionDeathRecipient(const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor) :
|
||||
mAnomalyAlarmMonitor(anomalyAlarmMonitor),
|
||||
mPeriodicAlarmMonitor(periodicAlarmMonitor) {}
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
private:
|
||||
const sp<AnomalyMonitor> mAnomalyMonitor;
|
||||
sp<AlarmMonitor> mAnomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> mPeriodicAlarmMonitor;
|
||||
};
|
||||
|
||||
CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor)
|
||||
: mAnomalyMonitor(anomalyMonitor) {
|
||||
}
|
||||
|
||||
void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
|
||||
ALOGW("statscompanion service died");
|
||||
mAnomalyMonitor->setStatsCompanionService(nullptr);
|
||||
mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
|
||||
mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
|
||||
SubscriberReporter::getInstance().setStatsCompanionService(nullptr);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
StatsService::StatsService(const sp<Looper>& handlerLooper)
|
||||
: mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
|
||||
{
|
||||
: mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
|
||||
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
|
||||
if (sc != nullptr) {
|
||||
sc->setAnomalyAlarm(timeMillis);
|
||||
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
|
||||
}
|
||||
},
|
||||
[](const sp<IStatsCompanionService>& sc) {
|
||||
if (sc != nullptr) {
|
||||
sc->cancelAnomalyAlarm();
|
||||
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
|
||||
}
|
||||
})),
|
||||
mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
|
||||
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
|
||||
if (sc != nullptr) {
|
||||
sc->setAlarmForSubscriberTriggering(timeMillis);
|
||||
StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
|
||||
}
|
||||
},
|
||||
[](const sp<IStatsCompanionService>& sc) {
|
||||
if (sc != nullptr) {
|
||||
sc->cancelAlarmForSubscriberTriggering();
|
||||
StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
|
||||
}
|
||||
|
||||
})) {
|
||||
mUidMap = new UidMap();
|
||||
StatsPuller::SetUidMap(mUidMap);
|
||||
mConfigManager = new ConfigManager();
|
||||
mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, getElapsedRealtimeSec(),
|
||||
[this](const ConfigKey& key) {
|
||||
sp<IStatsCompanionService> sc = getStatsCompanionService();
|
||||
auto receiver = mConfigManager->GetConfigReceiver(key);
|
||||
if (sc == nullptr) {
|
||||
VLOG("Could not find StatsCompanionService");
|
||||
} else if (receiver == nullptr) {
|
||||
VLOG("Statscompanion could not find a broadcast receiver for %s",
|
||||
key.ToString().c_str());
|
||||
} else {
|
||||
sc->sendDataBroadcast(receiver);
|
||||
}
|
||||
mProcessor = new StatsLogProcessor(mUidMap, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
|
||||
getElapsedRealtimeSec(), [this](const ConfigKey& key) {
|
||||
sp<IStatsCompanionService> sc = getStatsCompanionService();
|
||||
auto receiver = mConfigManager->GetConfigReceiver(key);
|
||||
if (sc == nullptr) {
|
||||
VLOG("Could not find StatsCompanionService");
|
||||
} else if (receiver == nullptr) {
|
||||
VLOG("Statscompanion could not find a broadcast receiver for %s",
|
||||
key.ToString().c_str());
|
||||
} else {
|
||||
sc->sendDataBroadcast(receiver);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
mConfigManager->AddListener(mProcessor);
|
||||
@ -622,7 +646,8 @@ status_t StatsService::cmd_dump_memory_info(FILE* out) {
|
||||
|
||||
status_t StatsService::cmd_clear_puller_cache(FILE* out) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
|
||||
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
|
||||
ipc->getCallingPid(), ipc->getCallingUid());
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
int cleared = mStatsPullerManager.ForceClearPullerCache();
|
||||
fprintf(out, "Puller removed %d cached data!\n", cleared);
|
||||
@ -677,18 +702,40 @@ Status StatsService::informAnomalyAlarmFired() {
|
||||
return Status::fromExceptionCode(Status::EX_SECURITY,
|
||||
"Only system uid can call informAnomalyAlarmFired");
|
||||
}
|
||||
|
||||
uint64_t currentTimeSec = getElapsedRealtimeSec();
|
||||
std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
|
||||
mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
|
||||
if (anomalySet.size() > 0) {
|
||||
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
|
||||
mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
|
||||
if (alarmSet.size() > 0) {
|
||||
VLOG("Found an anomaly alarm that fired.");
|
||||
mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
|
||||
mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
|
||||
} else {
|
||||
VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled.");
|
||||
}
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
Status StatsService::informAlarmForSubscriberTriggeringFired() {
|
||||
VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
|
||||
|
||||
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
|
||||
return Status::fromExceptionCode(
|
||||
Status::EX_SECURITY,
|
||||
"Only system uid can call informAlarmForSubscriberTriggeringFired");
|
||||
}
|
||||
|
||||
uint64_t currentTimeSec = time(nullptr);
|
||||
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
|
||||
mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
|
||||
if (alarmSet.size() > 0) {
|
||||
VLOG("Found periodic alarm fired.");
|
||||
mProcessor->onPeriodicAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
|
||||
} else {
|
||||
ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
|
||||
}
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
Status StatsService::informPollAlarmFired() {
|
||||
VLOG("StatsService::informPollAlarmFired was called");
|
||||
|
||||
@ -773,10 +820,11 @@ Status StatsService::statsCompanionReady() {
|
||||
"statscompanion unavailable despite it contacting statsd!");
|
||||
}
|
||||
VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
|
||||
IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
|
||||
mAnomalyMonitor->setStatsCompanionService(statsCompanion);
|
||||
IInterface::asBinder(statsCompanion)->linkToDeath(
|
||||
new CompanionDeathRecipient(mAnomalyAlarmMonitor, mPeriodicAlarmMonitor));
|
||||
mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
|
||||
mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
|
||||
SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion);
|
||||
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#define STATS_SERVICE_H
|
||||
|
||||
#include "StatsLogProcessor.h"
|
||||
#include "anomaly/AnomalyMonitor.h"
|
||||
#include "anomaly/AlarmMonitor.h"
|
||||
#include "config/ConfigManager.h"
|
||||
#include "external/StatsPullerManager.h"
|
||||
#include "packages/UidMap.h"
|
||||
@ -58,6 +58,8 @@ public:
|
||||
virtual Status statsCompanionReady();
|
||||
virtual Status informAnomalyAlarmFired();
|
||||
virtual Status informPollAlarmFired();
|
||||
virtual Status informAlarmForSubscriberTriggeringFired();
|
||||
|
||||
virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
|
||||
const vector<String16>& app);
|
||||
virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version);
|
||||
@ -244,9 +246,14 @@ private:
|
||||
sp<StatsLogProcessor> mProcessor;
|
||||
|
||||
/**
|
||||
* The anomaly detector.
|
||||
* The alarm monitor for anomaly detection.
|
||||
*/
|
||||
const sp<AnomalyMonitor> mAnomalyMonitor;
|
||||
const sp<AlarmMonitor> mAnomalyAlarmMonitor;
|
||||
|
||||
/**
|
||||
* The alarm monitor for alarms to directly trigger subscriber.
|
||||
*/
|
||||
const sp<AlarmMonitor> mPeriodicAlarmMonitor;
|
||||
|
||||
/**
|
||||
* Whether this is an eng build.
|
||||
|
@ -17,21 +17,24 @@
|
||||
#define DEBUG false
|
||||
#include "Log.h"
|
||||
|
||||
#include "anomaly/AnomalyMonitor.h"
|
||||
#include "anomaly/AlarmMonitor.h"
|
||||
#include "guardrail/StatsdStats.h"
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
|
||||
: mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
|
||||
}
|
||||
AlarmMonitor::AlarmMonitor(
|
||||
uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
|
||||
const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
|
||||
const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm)
|
||||
: mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
|
||||
mUpdateAlarm(updateAlarm),
|
||||
mCancelAlarm(cancelAlarm) {}
|
||||
|
||||
AnomalyMonitor::~AnomalyMonitor() {
|
||||
}
|
||||
AlarmMonitor::~AlarmMonitor() {}
|
||||
|
||||
void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
|
||||
void AlarmMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
|
||||
mStatsCompanionService = statsCompanionService;
|
||||
@ -40,13 +43,13 @@ void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCo
|
||||
return;
|
||||
}
|
||||
VLOG("Creating link to statsCompanionService");
|
||||
const sp<const AnomalyAlarm> top = mPq.top();
|
||||
const sp<const InternalAlarm> top = mPq.top();
|
||||
if (top != nullptr) {
|
||||
updateRegisteredAlarmTime_l(top->timestampSec);
|
||||
}
|
||||
}
|
||||
|
||||
void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
|
||||
void AlarmMonitor::add(sp<const InternalAlarm> alarm) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
if (alarm == nullptr) {
|
||||
ALOGW("Asked to add a null alarm.");
|
||||
@ -66,7 +69,7 @@ void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
|
||||
}
|
||||
}
|
||||
|
||||
void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
|
||||
void AlarmMonitor::remove(sp<const InternalAlarm> alarm) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
if (alarm == nullptr) {
|
||||
ALOGW("Asked to remove a null alarm.");
|
||||
@ -89,13 +92,13 @@ void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
|
||||
|
||||
// More efficient than repeatedly calling remove(mPq.top()) since it batches the
|
||||
// updates to the registered alarm.
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> AlarmMonitor::popSoonerThan(
|
||||
uint32_t timestampSec) {
|
||||
VLOG("Removing alarms with time <= %u", timestampSec);
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> oldAlarms;
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
|
||||
for (sp<const InternalAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
|
||||
t = mPq.top()) {
|
||||
oldAlarms.insert(t);
|
||||
mPq.pop(); // remove t
|
||||
@ -113,25 +116,19 @@ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popS
|
||||
return oldAlarms;
|
||||
}
|
||||
|
||||
void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
|
||||
void AlarmMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
|
||||
VLOG("Updating reg alarm time to %u", timestampSec);
|
||||
mRegisteredAlarmTimeSec = timestampSec;
|
||||
if (mStatsCompanionService != nullptr) {
|
||||
mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
|
||||
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
|
||||
}
|
||||
mUpdateAlarm(mStatsCompanionService, secToMs(mRegisteredAlarmTimeSec));
|
||||
}
|
||||
|
||||
void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
|
||||
void AlarmMonitor::cancelRegisteredAlarmTime_l() {
|
||||
VLOG("Cancelling reg alarm.");
|
||||
mRegisteredAlarmTimeSec = 0;
|
||||
if (mStatsCompanionService != nullptr) {
|
||||
mStatsCompanionService->cancelAnomalyAlarm();
|
||||
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
|
||||
}
|
||||
mCancelAlarm(mStatsCompanionService);
|
||||
}
|
||||
|
||||
int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
|
||||
int64_t AlarmMonitor::secToMs(uint32_t timeSec) {
|
||||
return ((int64_t)timeSec) * 1000;
|
||||
}
|
||||
|
@ -41,33 +41,34 @@ namespace statsd {
|
||||
* threshold.
|
||||
* Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
|
||||
*/
|
||||
struct AnomalyAlarm : public RefBase {
|
||||
AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
|
||||
struct InternalAlarm : public RefBase {
|
||||
InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
|
||||
}
|
||||
|
||||
const uint32_t timestampSec;
|
||||
|
||||
/** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
|
||||
/** InternalAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
|
||||
struct SmallerTimestamp {
|
||||
bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
|
||||
bool operator()(sp<const InternalAlarm> a, sp<const InternalAlarm> b) const {
|
||||
return (a->timestampSec < b->timestampSec);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: Rename this file to AnomalyAlarmMonitor.
|
||||
/**
|
||||
* Manages alarms for Anomaly Detection.
|
||||
* Manages internal alarms that may get registered with the AlarmManager.
|
||||
*/
|
||||
class AnomalyMonitor : public RefBase {
|
||||
class AlarmMonitor : public RefBase {
|
||||
public:
|
||||
/**
|
||||
* @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
|
||||
* from the registered alarm by more than this amount, update the registered
|
||||
* alarm.
|
||||
*/
|
||||
AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
|
||||
~AnomalyMonitor();
|
||||
AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
|
||||
const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
|
||||
const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm);
|
||||
~AlarmMonitor();
|
||||
|
||||
/**
|
||||
* Tells AnomalyMonitor what IStatsCompanionService to use and, if
|
||||
@ -80,20 +81,20 @@ public:
|
||||
/**
|
||||
* Adds the given alarm (reference) to the queue.
|
||||
*/
|
||||
void add(sp<const AnomalyAlarm> alarm);
|
||||
void add(sp<const InternalAlarm> alarm);
|
||||
|
||||
/**
|
||||
* Removes the given alarm (reference) from the queue.
|
||||
* Note that alarm comparison is reference-based; if another alarm exists
|
||||
* with the same timestampSec, that alarm will still remain in the queue.
|
||||
*/
|
||||
void remove(sp<const AnomalyAlarm> alarm);
|
||||
void remove(sp<const InternalAlarm> alarm);
|
||||
|
||||
/**
|
||||
* Returns and removes all alarms whose timestamp <= the given timestampSec.
|
||||
* Always updates the registered alarm if return is non-empty.
|
||||
*/
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> popSoonerThan(
|
||||
uint32_t timestampSec);
|
||||
|
||||
/**
|
||||
@ -119,7 +120,7 @@ private:
|
||||
/**
|
||||
* Priority queue of alarms, prioritized by soonest alarm.timestampSec.
|
||||
*/
|
||||
indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
|
||||
indexed_priority_queue<InternalAlarm, InternalAlarm::SmallerTimestamp> mPq;
|
||||
|
||||
/**
|
||||
* Binder interface for communicating with StatsCompanionService.
|
||||
@ -146,6 +147,13 @@ private:
|
||||
|
||||
/** Converts uint32 timestamp in seconds to a Java long in msec. */
|
||||
int64_t secToMs(uint32_t timeSec);
|
||||
|
||||
// Callback function to update the alarm via StatsCompanionService.
|
||||
std::function<void(const sp<IStatsCompanionService>, int64_t)> mUpdateAlarm;
|
||||
|
||||
// Callback function to cancel the alarm via StatsCompanionService.
|
||||
std::function<void(const sp<IStatsCompanionService>)> mCancelAlarm;
|
||||
|
||||
};
|
||||
|
||||
} // namespace statsd
|
79
cmds/statsd/src/anomaly/AlarmTracker.cpp
Normal file
79
cmds/statsd/src/anomaly/AlarmTracker.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define DEBUG true // STOPSHIP if true
|
||||
#include "Log.h"
|
||||
|
||||
#include "anomaly/AlarmTracker.h"
|
||||
#include "anomaly/subscriber_util.h"
|
||||
#include "HashableDimensionKey.h"
|
||||
#include "stats_util.h"
|
||||
#include "storage/StorageManager.h"
|
||||
|
||||
#include <statslog.h>
|
||||
#include <time.h>
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
AlarmTracker::AlarmTracker(uint64_t startMillis,
|
||||
const Alarm& alarm, const ConfigKey& configKey,
|
||||
const sp<AlarmMonitor>& alarmMonitor)
|
||||
: mAlarmConfig(alarm),
|
||||
mConfigKey(configKey),
|
||||
mAlarmMonitor(alarmMonitor) {
|
||||
VLOG("AlarmTracker() called");
|
||||
mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
|
||||
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
|
||||
mAlarmMonitor->add(mInternalAlarm);
|
||||
}
|
||||
|
||||
AlarmTracker::~AlarmTracker() {
|
||||
VLOG("~AlarmTracker() called");
|
||||
if (mInternalAlarm != nullptr) {
|
||||
mAlarmMonitor->remove(mInternalAlarm);
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmTracker::addSubscription(const Subscription& subscription) {
|
||||
mSubscriptions.push_back(subscription);
|
||||
}
|
||||
|
||||
uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) {
|
||||
int periodsForward = (currentTimeSec - mAlarmSec) * MS_PER_SEC / mAlarmConfig.period_millis();
|
||||
return mAlarmSec + (periodsForward + 1) * mAlarmConfig.period_millis() / MS_PER_SEC;
|
||||
}
|
||||
|
||||
void AlarmTracker::informAlarmsFired(
|
||||
const uint64_t& timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
|
||||
if (firedAlarms.empty() || firedAlarms.find(mInternalAlarm) == firedAlarms.end()) {
|
||||
return;
|
||||
}
|
||||
if (!mSubscriptions.empty()) {
|
||||
triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
|
||||
mSubscriptions);
|
||||
}
|
||||
firedAlarms.erase(mInternalAlarm);
|
||||
mAlarmSec = findNextAlarmSec(timestampNs / NS_PER_SEC);
|
||||
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
|
||||
mAlarmMonitor->add(mInternalAlarm);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
76
cmds/statsd/src/anomaly/AlarmTracker.h
Normal file
76
cmds/statsd/src/anomaly/AlarmTracker.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest_prod.h>
|
||||
|
||||
#include "AlarmMonitor.h"
|
||||
#include "config/ConfigKey.h"
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alarm
|
||||
|
||||
#include <android/os/IStatsCompanionService.h>
|
||||
#include <stdlib.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
using android::os::IStatsCompanionService;
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
class AlarmTracker : public virtual RefBase {
|
||||
public:
|
||||
AlarmTracker(uint64_t startMillis,
|
||||
const Alarm& alarm, const ConfigKey& configKey,
|
||||
const sp<AlarmMonitor>& subscriberAlarmMonitor);
|
||||
|
||||
virtual ~AlarmTracker();
|
||||
|
||||
void onAlarmFired();
|
||||
|
||||
void addSubscription(const Subscription& subscription);
|
||||
|
||||
void informAlarmsFired(const uint64_t& timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms);
|
||||
|
||||
protected:
|
||||
uint64_t findNextAlarmSec(uint64_t currentTimeMillis);
|
||||
|
||||
// statsd_config.proto Alarm message that defines this tracker.
|
||||
const Alarm mAlarmConfig;
|
||||
|
||||
// A reference to the Alarm's config key.
|
||||
const ConfigKey& mConfigKey;
|
||||
|
||||
// The subscriptions that depend on this alarm.
|
||||
std::vector<Subscription> mSubscriptions;
|
||||
|
||||
// Alarm monitor.
|
||||
sp<AlarmMonitor> mAlarmMonitor;
|
||||
|
||||
// The current expected alarm time in seconds.
|
||||
uint64_t mAlarmSec;
|
||||
|
||||
// The current alarm.
|
||||
sp<const InternalAlarm> mInternalAlarm;
|
||||
|
||||
FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
@ -18,6 +18,7 @@
|
||||
#include "Log.h"
|
||||
|
||||
#include "AnomalyTracker.h"
|
||||
#include "subscriber_util.h"
|
||||
#include "external/Perfetto.h"
|
||||
#include "guardrail/StatsdStats.h"
|
||||
#include "subscriber/IncidentdReporter.h"
|
||||
@ -231,40 +232,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs,
|
||||
}
|
||||
|
||||
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
|
||||
VLOG("informSubscribers called.");
|
||||
if (mSubscriptions.empty()) {
|
||||
// The config just wanted to log the anomaly. That's fine.
|
||||
VLOG("No Subscriptions were associated with the alert.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const Subscription& subscription : mSubscriptions) {
|
||||
if (subscription.probability_of_informing() < 1
|
||||
&& ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) {
|
||||
// Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
|
||||
// The config writer was advised to use -0.1 and 1.1 for never/always.
|
||||
ALOGI("Fate decided that a subscriber would not be informed.");
|
||||
continue;
|
||||
}
|
||||
switch (subscription.subscriber_information_case()) {
|
||||
case Subscription::SubscriberInformationCase::kIncidentdDetails:
|
||||
if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
|
||||
ALOGW("Failed to generate incident report.");
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kPerfettoDetails:
|
||||
if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
|
||||
ALOGW("Failed to generate prefetto traces.");
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
|
||||
SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription,
|
||||
key);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <gtest/gtest_prod.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "AnomalyMonitor.h"
|
||||
#include "AlarmMonitor.h"
|
||||
#include "config/ConfigKey.h"
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
|
||||
#include "stats_util.h" // HashableDimensionKey and DimToValMap
|
||||
@ -64,9 +64,9 @@ public:
|
||||
void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
|
||||
const MetricDimensionKey& key, const int64_t& currentBucketValue);
|
||||
|
||||
// Init the AnomalyMonitor which is shared across anomaly trackers.
|
||||
virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
|
||||
return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
|
||||
// Init the AlarmMonitor which is shared across anomaly trackers.
|
||||
virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) {
|
||||
return; // Base AnomalyTracker class has no need for the AlarmMonitor.
|
||||
}
|
||||
|
||||
// Helper function to return the sum value of past buckets at given dimension.
|
||||
@ -92,11 +92,10 @@ public:
|
||||
}
|
||||
|
||||
// Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
|
||||
// and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
|
||||
virtual void informAlarmsFired(
|
||||
const uint64_t& timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
|
||||
return; // The base AnomalyTracker class doesn't have alarms.
|
||||
// and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor.
|
||||
virtual void informAlarmsFired(const uint64_t& timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
|
||||
return; // The base AnomalyTracker class doesn't have alarms.
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -24,8 +24,9 @@ namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey)
|
||||
: AnomalyTracker(alert, configKey) {
|
||||
DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
|
||||
const sp<AlarmMonitor>& alarmMonitor)
|
||||
: AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
|
||||
}
|
||||
|
||||
DurationAnomalyTracker::~DurationAnomalyTracker() {
|
||||
@ -59,10 +60,10 @@ void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
|
||||
VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period");
|
||||
timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1;
|
||||
}
|
||||
sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
|
||||
sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec};
|
||||
mAlarms.insert({dimensionKey, alarm});
|
||||
if (mAnomalyMonitor != nullptr) {
|
||||
mAnomalyMonitor->add(alarm);
|
||||
if (mAlarmMonitor != nullptr) {
|
||||
mAlarmMonitor->add(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,8 +71,8 @@ void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey) {
|
||||
auto itr = mAlarms.find(dimensionKey);
|
||||
if (itr != mAlarms.end()) {
|
||||
mAlarms.erase(dimensionKey);
|
||||
if (mAnomalyMonitor != nullptr) {
|
||||
mAnomalyMonitor->remove(itr->second);
|
||||
if (mAlarmMonitor != nullptr) {
|
||||
mAlarmMonitor->remove(itr->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,16 +87,16 @@ void DurationAnomalyTracker::stopAllAlarms() {
|
||||
}
|
||||
}
|
||||
|
||||
void DurationAnomalyTracker::informAlarmsFired(
|
||||
const uint64_t& timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
|
||||
void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
|
||||
|
||||
if (firedAlarms.empty() || mAlarms.empty()) return;
|
||||
// Find the intersection of firedAlarms and mAlarms.
|
||||
// The for loop is inefficient, since it loops over all keys, but that's okay since it is very
|
||||
// seldomly called. The alternative would be having AnomalyAlarms store information about the
|
||||
// seldomly called. The alternative would be having InternalAlarms store information about the
|
||||
// DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
|
||||
// is rarely ever called.
|
||||
unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
|
||||
unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms;
|
||||
for (const auto& kv : mAlarms) {
|
||||
if (firedAlarms.count(kv.second) > 0) {
|
||||
matchedAlarms.insert({kv.first, kv.second});
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnomalyMonitor.h"
|
||||
#include "AlarmMonitor.h"
|
||||
#include "AnomalyTracker.h"
|
||||
|
||||
namespace android {
|
||||
@ -27,7 +27,8 @@ using std::unordered_map;
|
||||
|
||||
class DurationAnomalyTracker : public virtual AnomalyTracker {
|
||||
public:
|
||||
DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey);
|
||||
DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
|
||||
const sp<AlarmMonitor>& alarmMonitor);
|
||||
|
||||
virtual ~DurationAnomalyTracker();
|
||||
|
||||
@ -40,11 +41,6 @@ public:
|
||||
// Stop all the alarms owned by this tracker.
|
||||
void stopAllAlarms();
|
||||
|
||||
// Init the AnomalyMonitor which is shared across anomaly trackers.
|
||||
void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) override {
|
||||
mAnomalyMonitor = anomalyMonitor;
|
||||
}
|
||||
|
||||
// Declares the anomaly when the alarm expired given the current timestamp.
|
||||
void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
|
||||
const uint64_t& timestampNs);
|
||||
@ -53,17 +49,16 @@ public:
|
||||
// and removes it from firedAlarms.
|
||||
// Note that this will generally be called from a different thread from the other functions;
|
||||
// the caller is responsible for thread safety.
|
||||
void informAlarmsFired(
|
||||
const uint64_t& timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
|
||||
void informAlarmsFired(const uint64_t& timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) override;
|
||||
|
||||
protected:
|
||||
// The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
|
||||
// are still active.
|
||||
std::unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> mAlarms;
|
||||
std::unordered_map<MetricDimensionKey, sp<const InternalAlarm>> mAlarms;
|
||||
|
||||
// Anomaly alarm monitor.
|
||||
sp<AnomalyMonitor> mAnomalyMonitor;
|
||||
sp<AlarmMonitor> mAlarmMonitor;
|
||||
|
||||
// Resets all bucket data. For use when all the data gets stale.
|
||||
void resetStorage() override;
|
||||
|
75
cmds/statsd/src/anomaly/subscriber_util.cpp
Normal file
75
cmds/statsd/src/anomaly/subscriber_util.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define DEBUG true // STOPSHIP if true
|
||||
#include "Log.h"
|
||||
|
||||
#include <android/os/IIncidentManager.h>
|
||||
#include <android/os/IncidentReportArgs.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
|
||||
#include "external/Perfetto.h"
|
||||
#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
|
||||
#include "subscriber/IncidentdReporter.h"
|
||||
#include "subscriber/SubscriberReporter.h"
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
void triggerSubscribers(const int64_t rule_id,
|
||||
const MetricDimensionKey& dimensionKey,
|
||||
const ConfigKey& configKey,
|
||||
const std::vector<Subscription>& subscriptions) {
|
||||
VLOG("informSubscribers called.");
|
||||
if (subscriptions.empty()) {
|
||||
VLOG("No Subscriptions were associated.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const Subscription& subscription : subscriptions) {
|
||||
if (subscription.probability_of_informing() < 1
|
||||
&& ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) {
|
||||
// Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
|
||||
// The config writer was advised to use -0.1 and 1.1 for never/always.
|
||||
ALOGI("Fate decided that a subscriber would not be informed.");
|
||||
continue;
|
||||
}
|
||||
switch (subscription.subscriber_information_case()) {
|
||||
case Subscription::SubscriberInformationCase::kIncidentdDetails:
|
||||
if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) {
|
||||
ALOGW("Failed to generate incident report.");
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kPerfettoDetails:
|
||||
if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
|
||||
ALOGW("Failed to generate prefetto traces.");
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
|
||||
SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription,
|
||||
dimensionKey);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
34
cmds/statsd/src/anomaly/subscriber_util.h
Normal file
34
cmds/statsd/src/anomaly/subscriber_util.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config/ConfigKey.h"
|
||||
#include "HashableDimensionKey.h"
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
void triggerSubscribers(const int64_t rule_id,
|
||||
const MetricDimensionKey& dimensionKey,
|
||||
const ConfigKey& configKey,
|
||||
const std::vector<Subscription>& subscriptions);
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
2
cmds/statsd/src/external/Perfetto.h
vendored
2
cmds/statsd/src/external/Perfetto.h
vendored
@ -16,6 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/os/StatsLogEventWrapper.h>
|
||||
|
||||
using android::os::StatsLogEventWrapper;
|
||||
|
||||
namespace android {
|
||||
|
@ -47,11 +47,13 @@ const int FIELD_ID_UIDMAP_STATS = 8;
|
||||
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
|
||||
// const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
|
||||
const int FIELD_ID_LOGGER_ERROR_STATS = 11;
|
||||
const int FIELD_ID_SUBSCRIBER_ALARM_STATS = 12;
|
||||
|
||||
const int FIELD_ID_ATOM_STATS_TAG = 1;
|
||||
const int FIELD_ID_ATOM_STATS_COUNT = 2;
|
||||
|
||||
const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
|
||||
const int FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED = 1;
|
||||
|
||||
const int FIELD_ID_LOGGER_STATS_TIME = 1;
|
||||
const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2;
|
||||
@ -248,6 +250,11 @@ void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
|
||||
mAnomalyAlarmRegisteredStats++;
|
||||
}
|
||||
|
||||
void StatsdStats::noteRegisteredPeriodicAlarmChanged() {
|
||||
lock_guard<std::mutex> lock(mLock);
|
||||
mPeriodicAlarmRegisteredStats++;
|
||||
}
|
||||
|
||||
void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) {
|
||||
lock_guard<std::mutex> lock(mLock);
|
||||
mPulledAtomStats[pullAtomId].minPullIntervalSec = intervalSec;
|
||||
@ -297,6 +304,7 @@ void StatsdStats::resetInternalLocked() {
|
||||
std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
|
||||
mAlertStats.clear();
|
||||
mAnomalyAlarmRegisteredStats = 0;
|
||||
mPeriodicAlarmRegisteredStats = 0;
|
||||
mMatcherStats.clear();
|
||||
mLoggerErrors.clear();
|
||||
for (auto& config : mConfigStats) {
|
||||
@ -462,6 +470,11 @@ void StatsdStats::dumpStats(FILE* out) const {
|
||||
fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
|
||||
}
|
||||
|
||||
if (mPeriodicAlarmRegisteredStats > 0) {
|
||||
fprintf(out, "********SubscriberAlarmStats stats***********\n");
|
||||
fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
|
||||
}
|
||||
|
||||
fprintf(out,
|
||||
"UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
|
||||
"lost=%d\n",
|
||||
@ -531,6 +544,13 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
if (mPeriodicAlarmRegisteredStats > 0) {
|
||||
long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SUBSCRIBER_ALARM_STATS);
|
||||
proto.write(FIELD_TYPE_INT32 | FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED,
|
||||
mPeriodicAlarmRegisteredStats);
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
const int numBytes = mUidMapStats.ByteSize();
|
||||
vector<char> buffer(numBytes);
|
||||
mUidMapStats.SerializeToArray(&buffer[0], numBytes);
|
||||
|
@ -169,6 +169,11 @@ public:
|
||||
*/
|
||||
void noteRegisteredAnomalyAlarmChanged();
|
||||
|
||||
/**
|
||||
* Report that statsd modified the periodic alarm registered with StatsCompanionService.
|
||||
*/
|
||||
void noteRegisteredPeriodicAlarmChanged();
|
||||
|
||||
/**
|
||||
* Records the number of snapshot and delta entries that are being dropped from the uid map.
|
||||
*/
|
||||
@ -264,6 +269,9 @@ private:
|
||||
// StatsCompanionService.
|
||||
int mAnomalyAlarmRegisteredStats = 0;
|
||||
|
||||
// Stores the number of times statsd registers the periodic alarm changes
|
||||
int mPeriodicAlarmRegisteredStats = 0;
|
||||
|
||||
// Stores the number of times an anomaly detection alert has been declared
|
||||
// (per config, per alert name). The map size is capped by kMaxConfigCount.
|
||||
std::map<const ConfigKey, std::map<const int64_t, int>> mAlertStats;
|
||||
|
@ -109,9 +109,11 @@ DurationMetricProducer::~DurationMetricProducer() {
|
||||
VLOG("~DurationMetric() called");
|
||||
}
|
||||
|
||||
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
|
||||
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
|
||||
const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
|
||||
if (anomalyTracker != nullptr) {
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ public:
|
||||
|
||||
virtual ~DurationMetricProducer();
|
||||
|
||||
sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) override;
|
||||
sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
|
||||
|
||||
protected:
|
||||
void onMatchedLogEventInternalLocked(
|
||||
|
@ -124,7 +124,8 @@ public:
|
||||
}
|
||||
|
||||
/* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
|
||||
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) {
|
||||
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
|
||||
if (anomalyTracker != nullptr) {
|
||||
|
@ -49,13 +49,17 @@ namespace statsd {
|
||||
const int FIELD_ID_METRICS = 1;
|
||||
|
||||
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
|
||||
const long timeBaseSec, sp<UidMap> uidMap)
|
||||
const long timeBaseSec,
|
||||
const sp<UidMap> &uidMap,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor)
|
||||
: mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) {
|
||||
mConfigValid =
|
||||
initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers,
|
||||
mAllConditionTrackers,
|
||||
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
|
||||
mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
|
||||
initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, mTagIds, mAllAtomMatchers,
|
||||
mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
|
||||
mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
|
||||
mTrackerToConditionMap, mNoReportMetricIds);
|
||||
|
||||
if (config.allowed_log_source_size() == 0) {
|
||||
// TODO(b/70794411): uncomment the following line and remove the hard coded log source
|
||||
@ -340,16 +344,19 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void MetricsManager::onAnomalyAlarmFired(const uint64_t timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet) {
|
||||
void MetricsManager::onAnomalyAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
|
||||
for (const auto& itr : mAllAnomalyTrackers) {
|
||||
itr->informAlarmsFired(timestampNs, anomalySet);
|
||||
itr->informAlarmsFired(timestampNs, alarmSet);
|
||||
}
|
||||
}
|
||||
|
||||
void MetricsManager::setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
|
||||
for (auto& itr : mAllAnomalyTrackers) {
|
||||
itr->setAnomalyMonitor(anomalyMonitor);
|
||||
void MetricsManager::onPeriodicAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
|
||||
for (const auto& itr : mAllPeriodicAlarmTrackers) {
|
||||
itr->informAlarmsFired(timestampNs, alarmSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "anomaly/AnomalyMonitor.h"
|
||||
#include "anomaly/AlarmMonitor.h"
|
||||
#include "anomaly/AlarmTracker.h"
|
||||
#include "anomaly/AnomalyTracker.h"
|
||||
#include "condition/ConditionTracker.h"
|
||||
#include "config/ConfigKey.h"
|
||||
@ -36,7 +37,8 @@ namespace statsd {
|
||||
class MetricsManager : public PackageInfoListener {
|
||||
public:
|
||||
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec,
|
||||
sp<UidMap> uidMap);
|
||||
const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor);
|
||||
|
||||
virtual ~MetricsManager();
|
||||
|
||||
@ -47,9 +49,11 @@ public:
|
||||
|
||||
void onAnomalyAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet);
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
|
||||
|
||||
void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
|
||||
void onPeriodicAlarmFired(
|
||||
const uint64_t timestampNs,
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
|
||||
|
||||
void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
|
||||
const int64_t version) override;
|
||||
@ -120,6 +124,9 @@ private:
|
||||
// Hold all alert trackers.
|
||||
std::vector<sp<AnomalyTracker>> mAllAnomalyTrackers;
|
||||
|
||||
// Hold all periodic alarm trackers.
|
||||
std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers;
|
||||
|
||||
// To make the log processing more efficient, we want to do as much filtering as possible
|
||||
// before we go into individual trackers and conditions to match.
|
||||
|
||||
|
@ -17,16 +17,19 @@
|
||||
#define DEBUG false // STOPSHIP if true
|
||||
#include "Log.h"
|
||||
|
||||
#include "metrics_manager_util.h"
|
||||
|
||||
#include "../condition/CombinationConditionTracker.h"
|
||||
#include "../condition/SimpleConditionTracker.h"
|
||||
#include "../external/StatsPullerManager.h"
|
||||
#include "../matchers/CombinationLogMatchingTracker.h"
|
||||
#include "../matchers/SimpleLogMatchingTracker.h"
|
||||
#include "CountMetricProducer.h"
|
||||
#include "DurationMetricProducer.h"
|
||||
#include "EventMetricProducer.h"
|
||||
#include "GaugeMetricProducer.h"
|
||||
#include "ValueMetricProducer.h"
|
||||
#include "../metrics/CountMetricProducer.h"
|
||||
#include "../metrics/DurationMetricProducer.h"
|
||||
#include "../metrics/EventMetricProducer.h"
|
||||
#include "../metrics/GaugeMetricProducer.h"
|
||||
#include "../metrics/ValueMetricProducer.h"
|
||||
|
||||
#include "stats_util.h"
|
||||
|
||||
using std::set;
|
||||
@ -494,6 +497,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
|
||||
|
||||
bool initAlerts(const StatsdConfig& config,
|
||||
const unordered_map<int64_t, int>& metricProducerMap,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
vector<sp<MetricProducer>>& allMetricProducers,
|
||||
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
|
||||
unordered_map<int64_t, int> anomalyTrackerMap;
|
||||
@ -512,7 +516,7 @@ bool initAlerts(const StatsdConfig& config,
|
||||
}
|
||||
const int metricIndex = itr->second;
|
||||
sp<MetricProducer> metric = allMetricProducers[metricIndex];
|
||||
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
|
||||
if (anomalyTracker == nullptr) {
|
||||
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
|
||||
return false;
|
||||
@ -522,6 +526,9 @@ bool initAlerts(const StatsdConfig& config,
|
||||
}
|
||||
for (int i = 0; i < config.subscription_size(); ++i) {
|
||||
const Subscription& subscription = config.subscription(i);
|
||||
if (subscription.rule_type() != Subscription::ALERT) {
|
||||
continue;
|
||||
}
|
||||
if (subscription.subscriber_information_case() ==
|
||||
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
|
||||
ALOGW("subscription \"%lld\" has no subscriber info.\"",
|
||||
@ -540,13 +547,60 @@ bool initAlerts(const StatsdConfig& config,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor,
|
||||
const long timeBaseSec,
|
||||
vector<sp<AlarmTracker>>& allAlarmTrackers) {
|
||||
unordered_map<int64_t, int> alarmTrackerMap;
|
||||
uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC;
|
||||
for (int i = 0; i < config.alarm_size(); i++) {
|
||||
const Alarm& alarm = config.alarm(i);
|
||||
if (alarm.offset_millis() <= 0) {
|
||||
ALOGW("Alarm offset_millis should be larger than 0.");
|
||||
return false;
|
||||
}
|
||||
if (alarm.period_millis() <= 0) {
|
||||
ALOGW("Alarm period_millis should be larger than 0.");
|
||||
return false;
|
||||
}
|
||||
alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
|
||||
allAlarmTrackers.push_back(
|
||||
new AlarmTracker(startMillis, alarm, key, periodicAlarmMonitor));
|
||||
}
|
||||
for (int i = 0; i < config.subscription_size(); ++i) {
|
||||
const Subscription& subscription = config.subscription(i);
|
||||
if (subscription.rule_type() != Subscription::ALARM) {
|
||||
continue;
|
||||
}
|
||||
if (subscription.subscriber_information_case() ==
|
||||
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
|
||||
ALOGW("subscription \"%lld\" has no subscriber info.\"",
|
||||
(long long)subscription.id());
|
||||
return false;
|
||||
}
|
||||
const auto& itr = alarmTrackerMap.find(subscription.rule_id());
|
||||
if (itr == alarmTrackerMap.end()) {
|
||||
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
|
||||
(long long)subscription.id(), (long long)subscription.rule_id());
|
||||
return false;
|
||||
}
|
||||
const int trackerIndex = itr->second;
|
||||
allAlarmTrackers[trackerIndex]->addSubscription(subscription);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
|
||||
const UidMap& uidMap,
|
||||
const long timeBaseSec, set<int>& allTagIds,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor,
|
||||
const long timeBaseSec,
|
||||
set<int>& allTagIds,
|
||||
vector<sp<LogMatchingTracker>>& allAtomMatchers,
|
||||
vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
vector<sp<MetricProducer>>& allMetricProducers,
|
||||
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
|
||||
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
|
||||
unordered_map<int, std::vector<int>>& conditionToMetricMap,
|
||||
unordered_map<int, std::vector<int>>& trackerToMetricMap,
|
||||
unordered_map<int, std::vector<int>>& trackerToConditionMap,
|
||||
@ -573,10 +627,16 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
|
||||
ALOGE("initMetricProducers failed");
|
||||
return false;
|
||||
}
|
||||
if (!initAlerts(config, metricProducerMap, allMetricProducers, allAnomalyTrackers)) {
|
||||
if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
|
||||
allAnomalyTrackers)) {
|
||||
ALOGE("initAlerts failed");
|
||||
return false;
|
||||
}
|
||||
if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseSec, allPeriodicAlarmTrackers)) {
|
||||
ALOGE("initAlarms failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,16 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef METRIC_UTIL_H
|
||||
#define METRIC_UTIL_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "../anomaly/AlarmTracker.h"
|
||||
#include "../condition/ConditionTracker.h"
|
||||
#include "../external/StatsPullerManagerImpl.h"
|
||||
#include "../matchers/LogMatchingTracker.h"
|
||||
#include "../metrics/MetricProducer.h"
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
@ -93,11 +96,15 @@ bool initMetrics(
|
||||
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
|
||||
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
|
||||
const UidMap& uidMap,
|
||||
const long timeBaseSec, std::set<int>& allTagIds,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor,
|
||||
const long timeBaseSec,
|
||||
std::set<int>& allTagIds,
|
||||
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
|
||||
std::vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
std::vector<sp<MetricProducer>>& allMetricProducers,
|
||||
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
|
||||
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
|
||||
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
|
||||
@ -106,4 +113,3 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
#endif // METRIC_UTIL_H
|
||||
|
@ -164,4 +164,4 @@ message ConfigMetricsReportList {
|
||||
optional ConfigKey config_key = 1;
|
||||
|
||||
repeated ConfigMetricsReport reports = 2;
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +195,20 @@ void StorageManager::appendConfigMetricsReport(ProtoOutputStream& proto) {
|
||||
}
|
||||
}
|
||||
|
||||
bool StorageManager::readFileToString(const char* file, string* content) {
|
||||
int fd = open(file, O_RDONLY | O_CLOEXEC);
|
||||
bool res = false;
|
||||
if (fd != -1) {
|
||||
if (android::base::ReadFdToString(fd, content)) {
|
||||
res = true;
|
||||
} else {
|
||||
VLOG("Failed to read file %s\n", file);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap) {
|
||||
unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
|
||||
if (dir == NULL) {
|
||||
|
@ -36,6 +36,11 @@ public:
|
||||
*/
|
||||
static void writeFile(const char* file, const void* buffer, int numBytes);
|
||||
|
||||
/**
|
||||
* Reads the file content to the buffer.
|
||||
*/
|
||||
static bool readFileToString(const char* file, string* content);
|
||||
|
||||
/**
|
||||
* Deletes a single file given a file name.
|
||||
*/
|
||||
|
@ -28,10 +28,10 @@ namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
|
||||
const ConfigKey& configKey) {
|
||||
if (config.section_size() == 0) {
|
||||
VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(),
|
||||
VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
|
||||
configKey.GetUid(), (long long) configKey.GetId());
|
||||
return false;
|
||||
}
|
||||
@ -39,7 +39,7 @@ bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
|
||||
IncidentReportArgs incidentReport;
|
||||
|
||||
android::os::IncidentHeaderProto header;
|
||||
header.set_alert_id(alert.id());
|
||||
header.set_alert_id(rule_id);
|
||||
header.mutable_config_key()->set_uid(configKey.GetUid());
|
||||
header.mutable_config_key()->set_id(configKey.GetId());
|
||||
incidentReport.addHeader(header);
|
||||
|
@ -26,7 +26,7 @@ namespace statsd {
|
||||
/**
|
||||
* Calls incidentd to trigger an incident report and put in dropbox for uploading.
|
||||
*/
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
|
||||
bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
|
||||
const ConfigKey& configKey);
|
||||
|
||||
} // namespace statsd
|
||||
|
@ -12,28 +12,29 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "anomaly/AnomalyMonitor.h"
|
||||
#include "anomaly/AlarmMonitor.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace android::os::statsd;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
TEST(AnomalyMonitor, popSoonerThan) {
|
||||
TEST(AlarmMonitor, popSoonerThan) {
|
||||
std::string emptyMetricId;
|
||||
std::string emptyDimensionId;
|
||||
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> set;
|
||||
AnomalyMonitor am(2);
|
||||
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> set;
|
||||
AlarmMonitor am(2, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){});
|
||||
|
||||
set = am.popSoonerThan(5);
|
||||
EXPECT_TRUE(set.empty());
|
||||
|
||||
sp<const AnomalyAlarm> a = new AnomalyAlarm{10};
|
||||
sp<const AnomalyAlarm> b = new AnomalyAlarm{20};
|
||||
sp<const AnomalyAlarm> c = new AnomalyAlarm{20};
|
||||
sp<const AnomalyAlarm> d = new AnomalyAlarm{30};
|
||||
sp<const AnomalyAlarm> e = new AnomalyAlarm{40};
|
||||
sp<const AnomalyAlarm> f = new AnomalyAlarm{50};
|
||||
sp<const InternalAlarm> a = new InternalAlarm{10};
|
||||
sp<const InternalAlarm> b = new InternalAlarm{20};
|
||||
sp<const InternalAlarm> c = new InternalAlarm{20};
|
||||
sp<const InternalAlarm> d = new InternalAlarm{30};
|
||||
sp<const InternalAlarm> e = new InternalAlarm{40};
|
||||
sp<const InternalAlarm> f = new InternalAlarm{50};
|
||||
|
||||
am.add(a);
|
||||
am.add(b);
|
@ -65,8 +65,12 @@ MATCHER_P(StatsdConfigEq, id, 0) {
|
||||
const int64_t testConfigId = 12345;
|
||||
|
||||
TEST(ConfigManagerTest, TestFakeConfig) {
|
||||
auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, testConfigId),
|
||||
build_fake_config(), 1000, new UidMap());
|
||||
auto metricsManager = std::make_unique<MetricsManager>(
|
||||
ConfigKey(0, testConfigId), build_fake_config(), 1000, new UidMap(),
|
||||
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){}),
|
||||
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){}));
|
||||
EXPECT_TRUE(metricsManager->isConfigValid());
|
||||
}
|
||||
|
||||
|
@ -271,19 +271,25 @@ StatsdConfig buildCirclePredicates() {
|
||||
|
||||
TEST(MetricsManagerTest, TestGoodConfig) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildGoodConfig();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
|
||||
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
EXPECT_EQ(1u, allMetricProducers.size());
|
||||
@ -293,112 +299,148 @@ TEST(MetricsManagerTest, TestGoodConfig) {
|
||||
|
||||
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildDimensionMetricsWithMultiTags();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildCircleMatchers();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestMissingMatchers) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildMissingMatchers();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestMissingPredicate) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildMissingPredicate();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildCirclePredicates();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
|
||||
UidMap uidMap;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
StatsdConfig config = buildAlertWithUnknownMetric();
|
||||
set<int> allTagIds;
|
||||
vector<sp<LogMatchingTracker>> allAtomMatchers;
|
||||
vector<sp<ConditionTracker>> allConditionTrackers;
|
||||
vector<sp<MetricProducer>> allMetricProducers;
|
||||
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
|
||||
std::vector<sp<AlarmTracker>> allAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> trackerToConditionMap;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
|
||||
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
|
||||
anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseSec, allTagIds, allAtomMatchers,
|
||||
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
|
||||
allAlarmTrackers,
|
||||
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
|
||||
noReportMetricIds));
|
||||
}
|
||||
|
@ -41,7 +41,13 @@ using android::util::ProtoOutputStream;
|
||||
*/
|
||||
class MockMetricsManager : public MetricsManager {
|
||||
public:
|
||||
MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, new UidMap()) {
|
||||
MockMetricsManager() : MetricsManager(
|
||||
ConfigKey(1, 12345), StatsdConfig(), 1000,
|
||||
new UidMap(),
|
||||
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){}),
|
||||
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){})) {
|
||||
}
|
||||
|
||||
MOCK_METHOD0(byteSize, size_t());
|
||||
@ -50,9 +56,11 @@ public:
|
||||
|
||||
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
|
||||
sp<UidMap> m = new UidMap();
|
||||
sp<AnomalyMonitor> anomalyMonitor;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
// Construct the processor with a dummy sendBroadcast function that does nothing.
|
||||
StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {});
|
||||
StatsLogProcessor p(m, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
|
||||
[](const ConfigKey& key) {});
|
||||
|
||||
MockMetricsManager mockMetricsManager;
|
||||
|
||||
@ -67,11 +75,11 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
|
||||
|
||||
TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
|
||||
sp<UidMap> m = new UidMap();
|
||||
sp<AnomalyMonitor> anomalyMonitor;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> subscriberAlarmMonitor;
|
||||
int broadcastCount = 0;
|
||||
StatsLogProcessor p(m, anomalyMonitor, 0, [&broadcastCount](const ConfigKey& key) {
|
||||
broadcastCount++;
|
||||
});
|
||||
StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
||||
[&broadcastCount](const ConfigKey& key) { broadcastCount++; });
|
||||
|
||||
MockMetricsManager mockMetricsManager;
|
||||
|
||||
@ -93,9 +101,10 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
|
||||
|
||||
TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
|
||||
sp<UidMap> m = new UidMap();
|
||||
sp<AnomalyMonitor> anomalyMonitor;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> subscriberAlarmMonitor;
|
||||
int broadcastCount = 0;
|
||||
StatsLogProcessor p(m, anomalyMonitor, 0,
|
||||
StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
||||
[&broadcastCount](const ConfigKey& key) { broadcastCount++; });
|
||||
|
||||
MockMetricsManager mockMetricsManager;
|
||||
|
@ -36,9 +36,11 @@ const string kApp2 = "app2.sharing.1";
|
||||
|
||||
TEST(UidMapTest, TestIsolatedUID) {
|
||||
sp<UidMap> m = new UidMap();
|
||||
sp<AnomalyMonitor> anomalyMonitor;
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> subscriberAlarmMonitor;
|
||||
// Construct the processor with a dummy sendBroadcast function that does nothing.
|
||||
StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {});
|
||||
StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
||||
[](const ConfigKey& key) {});
|
||||
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
|
||||
addEvent.write(100); // parent UID
|
||||
addEvent.write(101); // isolated UID
|
||||
|
68
cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
Normal file
68
cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/anomaly/AlarmTracker.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace testing;
|
||||
using android::sp;
|
||||
using std::set;
|
||||
using std::unordered_map;
|
||||
using std::vector;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
const ConfigKey kConfigKey(0, 12345);
|
||||
|
||||
TEST(AlarmTrackerTest, TestTriggerTimestamp) {
|
||||
sp<AlarmMonitor> subscriberAlarmMonitor =
|
||||
new AlarmMonitor(100, [](const sp<IStatsCompanionService>&, int64_t){},
|
||||
[](const sp<IStatsCompanionService>&){});
|
||||
Alarm alarm;
|
||||
alarm.set_offset_millis(15 * MS_PER_SEC);
|
||||
alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr
|
||||
uint64_t startMillis = 100000000 * MS_PER_SEC;
|
||||
AlarmTracker tracker(startMillis, alarm, kConfigKey,
|
||||
subscriberAlarmMonitor);
|
||||
|
||||
EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
|
||||
|
||||
uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
|
||||
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
|
||||
subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
|
||||
EXPECT_TRUE(firedAlarmSet.empty());
|
||||
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
|
||||
EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
|
||||
|
||||
currentTimeSec = startMillis / MS_PER_SEC + 7000;
|
||||
firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
|
||||
EXPECT_EQ(firedAlarmSet.size(), 1u);
|
||||
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
|
||||
EXPECT_TRUE(firedAlarmSet.empty());
|
||||
EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15 + 2 * 60 * 60);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
@ -201,6 +201,7 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
|
||||
}
|
||||
|
||||
TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
uint64_t bucketStartTimeNs = 10000000000;
|
||||
uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
|
||||
uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
|
||||
@ -222,7 +223,7 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
|
||||
bucketStartTimeNs);
|
||||
countProducer.setBucketSize(60 * NS_PER_SEC);
|
||||
|
||||
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
EXPECT_TRUE(anomalyTracker != nullptr);
|
||||
|
||||
// Bucket is flushed yet.
|
||||
@ -315,6 +316,7 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
|
||||
}
|
||||
|
||||
TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
Alert alert;
|
||||
alert.set_id(11);
|
||||
alert.set_metric_id(1);
|
||||
@ -337,7 +339,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
|
||||
bucketStartTimeNs);
|
||||
countProducer.setBucketSize(60 * NS_PER_SEC);
|
||||
|
||||
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
|
||||
int tagId = 1;
|
||||
LogEvent event1(tagId, bucketStartTimeNs + 1);
|
||||
|
@ -239,6 +239,7 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
|
||||
}
|
||||
|
||||
TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
uint64_t bucketStartTimeNs = 10000000000;
|
||||
uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
|
||||
uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
|
||||
@ -263,7 +264,7 @@ TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
|
||||
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
|
||||
durationProducer.setBucketSize(60 * NS_PER_SEC);
|
||||
|
||||
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
EXPECT_TRUE(anomalyTracker != nullptr);
|
||||
|
||||
LogEvent start_event(tagId, startTimeNs);
|
||||
|
@ -129,6 +129,7 @@ TEST(GaugeMetricProducerTest, TestNoCondition) {
|
||||
}
|
||||
|
||||
TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
GaugeMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.set_bucket(ONE_MINUTE);
|
||||
@ -145,8 +146,9 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
|
||||
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
|
||||
-1 /* -1 means no pulling */, bucketStartTimeNs,
|
||||
pullerManager);
|
||||
|
||||
gaugeProducer.setBucketSize(60 * NS_PER_SEC);
|
||||
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
EXPECT_TRUE(anomalyTracker != nullptr);
|
||||
|
||||
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
|
||||
@ -339,6 +341,7 @@ TEST(GaugeMetricProducerTest, TestWithCondition) {
|
||||
}
|
||||
|
||||
TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
shared_ptr<MockStatsPullerManager> pullerManager =
|
||||
@ -363,7 +366,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
|
||||
alert.set_num_buckets(2);
|
||||
const int32_t refPeriodSec = 60;
|
||||
alert.set_refractory_period_secs(refPeriodSec);
|
||||
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
|
||||
int tagId = 1;
|
||||
std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
|
||||
|
@ -276,13 +276,15 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
|
||||
alert.set_num_buckets(2);
|
||||
const int32_t refPeriodSec = 45;
|
||||
alert.set_refractory_period_secs(refPeriodSec);
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, {anomalyTracker});
|
||||
|
||||
tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
|
||||
sp<const AnomalyAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
|
||||
sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
|
||||
EXPECT_EQ((long long)(53ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
|
||||
|
||||
// Remove the anomaly alarm when the duration is no longer fully met.
|
||||
@ -336,7 +338,9 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
|
||||
alert.set_num_buckets(2);
|
||||
const int32_t refPeriodSec = 45;
|
||||
alert.set_refractory_period_secs(refPeriodSec);
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, {anomalyTracker});
|
||||
@ -390,7 +394,9 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
|
||||
alert.set_num_buckets(2);
|
||||
const int32_t refPeriodSec = 45;
|
||||
alert.set_refractory_period_secs(refPeriodSec);
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, {anomalyTracker});
|
||||
|
@ -334,7 +334,9 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
|
||||
uint64_t bucketNum = 0;
|
||||
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
|
||||
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, {anomalyTracker});
|
||||
@ -403,7 +405,9 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
|
||||
uint64_t bucketNum = 0;
|
||||
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
|
||||
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, {anomalyTracker});
|
||||
@ -453,14 +457,16 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
|
||||
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
|
||||
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
|
||||
|
||||
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
|
||||
bucketSizeNs, false, {anomalyTracker});
|
||||
|
||||
tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
|
||||
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
|
||||
sp<const AnomalyAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
|
||||
sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
|
||||
EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
|
||||
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
|
||||
|
||||
@ -487,7 +493,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
|
||||
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
|
||||
|
||||
// Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time.
|
||||
std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> firedAlarms({alarm});
|
||||
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
|
||||
anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms);
|
||||
EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
|
||||
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
|
||||
|
@ -346,6 +346,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
|
||||
}
|
||||
|
||||
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(metricId);
|
||||
@ -365,7 +366,7 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
|
||||
-1 /*not pulled*/, bucketStartTimeNs);
|
||||
valueProducer.setBucketSize(60 * NS_PER_SEC);
|
||||
|
||||
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
|
||||
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
|
||||
|
||||
|
||||
shared_ptr<LogEvent> event1
|
||||
|
@ -391,9 +391,10 @@ std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
|
||||
sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
|
||||
const ConfigKey& key) {
|
||||
sp<UidMap> uidMap = new UidMap();
|
||||
sp<AnomalyMonitor> anomalyMonitor = new AnomalyMonitor(10); // 10 seconds
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
sp<StatsLogProcessor> processor = new StatsLogProcessor(
|
||||
uidMap, anomalyMonitor, timeBaseSec, [](const ConfigKey&){});
|
||||
uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
|
||||
processor->OnConfigUpdated(key, config);
|
||||
return processor;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ interface IStatsCompanionService {
|
||||
oneway void cancelAnomalyAlarm();
|
||||
|
||||
/**
|
||||
* Register a repeating alarm for polling to fire at the given timestamp and every
|
||||
* Register a repeating alarm for pulling to fire at the given timestamp and every
|
||||
* intervalMs thereafter (in ms since epoch).
|
||||
* If polling alarm had already been registered, it will be replaced by new one.
|
||||
* Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
|
||||
@ -49,9 +49,19 @@ interface IStatsCompanionService {
|
||||
*/
|
||||
oneway void setPullingAlarms(long timestampMs, long intervalMs);
|
||||
|
||||
/** Cancel any repeating polling alarm. */
|
||||
/** Cancel any repeating pulling alarm. */
|
||||
oneway void cancelPullingAlarms();
|
||||
|
||||
/**
|
||||
* Register an alarm when we want to trigger subscribers at the given
|
||||
* timestamp (in ms since epoch).
|
||||
* If an alarm had already been registered, it will be replaced by new one.
|
||||
*/
|
||||
oneway void setAlarmForSubscriberTriggering(long timestampMs);
|
||||
|
||||
/** Cancel any alarm for the purpose of subscriber triggering. */
|
||||
oneway void cancelAlarmForSubscriberTriggering();
|
||||
|
||||
/** Pull the specified data. Results will be sent to statsd when complete. */
|
||||
StatsLogEventWrapper[] pullData(int pullCode);
|
||||
|
||||
|
@ -46,6 +46,13 @@ interface IStatsManager {
|
||||
*/
|
||||
void informPollAlarmFired();
|
||||
|
||||
/**
|
||||
* Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for
|
||||
* determing what alarm subscriber to trigger.
|
||||
* Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
|
||||
*/
|
||||
void informAlarmForSubscriberTriggeringFired();
|
||||
|
||||
/**
|
||||
* Tells statsd to store data to disk.
|
||||
*/
|
||||
|
@ -100,6 +100,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
|
||||
|
||||
private final PendingIntent mAnomalyAlarmIntent;
|
||||
private final PendingIntent mPullingAlarmIntent;
|
||||
private final PendingIntent mPeriodicAlarmIntent;
|
||||
private final BroadcastReceiver mAppUpdateReceiver;
|
||||
private final BroadcastReceiver mUserUpdateReceiver;
|
||||
private final ShutdownEventReceiver mShutdownEventReceiver;
|
||||
@ -123,6 +124,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
|
||||
new Intent(mContext, AnomalyAlarmReceiver.class), 0);
|
||||
mPullingAlarmIntent = PendingIntent.getBroadcast(
|
||||
mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
|
||||
mPeriodicAlarmIntent = PendingIntent.getBroadcast(
|
||||
mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0);
|
||||
mAppUpdateReceiver = new AppUpdateReceiver();
|
||||
mUserUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
@ -329,7 +332,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ShutdownEventReceiver extends BroadcastReceiver {
|
||||
public final static class PeriodicAlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (DEBUG)
|
||||
Slog.d(TAG, "Time to poll something.");
|
||||
synchronized (sStatsdLock) {
|
||||
if (sStatsd == null) {
|
||||
Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Two-way call to statsd to retain AlarmManager wakelock
|
||||
sStatsd.informAlarmForSubscriberTriggeringFired();
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
|
||||
}
|
||||
}
|
||||
// AlarmManager releases its own wakelock here.
|
||||
}
|
||||
}
|
||||
|
||||
public final static class ShutdownEventReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
/**
|
||||
@ -384,6 +408,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void setAlarmForSubscriberTriggering(long timestampMs) {
|
||||
enforceCallingPermission();
|
||||
if (DEBUG)
|
||||
Slog.d(TAG, "Setting periodic alarm at " + timestampMs);
|
||||
final long callingToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
|
||||
// only fire when it awakens.
|
||||
// This alarm is inexact, leaving its exactness completely up to the OS optimizations.
|
||||
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAlarmForSubscriberTriggering() {
|
||||
enforceCallingPermission();
|
||||
if (DEBUG)
|
||||
Slog.d(TAG, "Cancelling periodic alarm");
|
||||
final long callingToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mAlarmManager.cancel(mPeriodicAlarmIntent);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void setPullingAlarms(long timestampMs, long intervalMs) {
|
||||
enforceCallingPermission();
|
||||
|
Reference in New Issue
Block a user