Merge "Alarm: wakes up statsd and notifies the subscribers."

This commit is contained in:
TreeHugger Robot
2018-02-27 23:08:31 +00:00
committed by Android (Google) Code Review
47 changed files with 896 additions and 237 deletions

View File

@ -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 \

View File

@ -40,7 +40,7 @@ public:
mValues = values;
}
HashableDimensionKey(){};
HashableDimensionKey() {};
HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};

View File

@ -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.

View File

@ -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);

View File

@ -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();
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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:

View File

@ -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});

View File

@ -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;

View 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

View 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

View File

@ -16,6 +16,8 @@
#pragma once
#include <android/os/StatsLogEventWrapper.h>
using android::os::StatsLogEventWrapper;
namespace android {

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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(

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -164,4 +164,4 @@ message ConfigMetricsReportList {
optional ConfigKey config_key = 1;
repeated ConfigMetricsReport reports = 2;
}
}

View File

@ -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) {

View File

@ -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.
*/

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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());
}

View File

@ -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));
}

View File

@ -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;

View File

@ -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

View 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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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});

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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.
*/

View File

@ -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();