diff options
30 files changed, 1052 insertions, 120 deletions
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 58ba42fb3519..54ade3563851 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -44,6 +44,7 @@ statsd_common_src := \ src/metrics/DurationMetricProducer.cpp \ src/metrics/duration_helper/OringDurationTracker.cpp \ src/metrics/duration_helper/MaxDurationTracker.cpp \ + src/metrics/ValueMetricProducer.cpp \ src/metrics/MetricsManager.cpp \ src/metrics/metrics_manager_util.cpp \ src/packages/UidMap.cpp \ diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index a856a271df4f..edb1a0f94e2b 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -65,7 +65,6 @@ void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) { StatsService::StatsService(const sp<Looper>& handlerLooper) : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better { - mStatsPullerManager = new StatsPullerManager(); mUidMap = new UidMap(); mConfigManager = new ConfigManager(); mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) { @@ -374,7 +373,7 @@ status_t StatsService::cmd_print_uid_map(FILE* out) { status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) { int s = atoi(args[1].c_str()); - auto stats = mStatsPullerManager->Pull(s); + auto stats = m_stats_puller_manager.Pull(s, time(nullptr)); for (const auto& it : stats) { fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str()); } @@ -441,8 +440,9 @@ Status StatsService::informPollAlarmFired() { "Only system uid can call informPollAlarmFired"); } + m_stats_puller_manager.OnAlarmFired(); + if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded"); - // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them. return Status::ok(); } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 7f046584b2d0..3930d319ce8d 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -27,7 +27,6 @@ #include <android/os/IStatsCallbacks.h> #include <android/os/IStatsCompanionService.h> #include <binder/IResultReceiver.h> -#include <binder/IShellCallback.h> #include <utils/Looper.h> #include <deque> @@ -158,7 +157,7 @@ private: /** * Fetches external metrics. */ - sp<StatsPullerManager> mStatsPullerManager; + StatsPullerManager& m_stats_puller_manager = StatsPullerManager::GetInstance(); /** * Tracks the configurations that have been passed to statsd. diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index e3ccb0635bab..88127194753f 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -139,6 +139,9 @@ static StatsdConfig build_fake_config() { int UID_PROCESS_STATE_TAG_ID = 27; int UID_PROCESS_STATE_UID_KEY = 1; + int KERNEL_WAKELOCK_TAG_ID = 41; + int KERNEL_WAKELOCK_NAME_KEY = 4; + // Count Screen ON events. CountMetric* metric = config.add_count_metric(); metric->set_metric_id(1); @@ -228,6 +231,17 @@ static StatsdConfig build_fake_config() { durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM); durationMetric->set_what("SCREEN_IS_ON"); + // Value metric to count KERNEL_WAKELOCK when screen turned on + ValueMetric* valueMetric = config.add_value_metric(); + valueMetric->set_metric_id(6); + valueMetric->set_what("KERNEL_WAKELOCK"); + valueMetric->set_value_field(1); + valueMetric->set_condition("SCREEN_IS_ON"); + keyMatcher = valueMetric->add_dimension(); + keyMatcher->set_key(KERNEL_WAKELOCK_NAME_KEY); + // This is for testing easier. We should never set bucket size this small. + valueMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L); + // Add an EventMetric to log process state change events. EventMetric* eventMetric = config.add_event_metric(); eventMetric->set_metric_id(9); diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp index ee072f80aa4a..521d3f6db236 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.cpp +++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ +#define DEBUG true #include "Log.h" #include <android/os/IStatsCompanionService.h> #include <binder/IPCThreadState.h> #include <private/android_filesystem_config.h> +#include "KernelWakelockPuller.h" #include "StatsService.h" -#include "external/KernelWakelockPuller.h" -#include "external/StatsPuller.h" using namespace android; using namespace android::base; @@ -37,7 +37,7 @@ const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20; // The reading and parsing are implemented in Java. It is not difficult to port over. But for now // let StatsCompanionService handle that and send the data back. -vector<StatsLogEventWrapper> KernelWakelockPuller::pull() { +vector<StatsLogEventWrapper> KernelWakelockPuller::Pull() { sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService(); vector<StatsLogEventWrapper> returned_value; if (statsCompanion != NULL) { diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h index c12806c1fc47..cc8059d80601 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.h +++ b/cmds/statsd/src/external/KernelWakelockPuller.h @@ -14,11 +14,10 @@ * limitations under the License. */ -#ifndef STATSD_KERNELWAKELOCKPULLER_H -#define STATSD_KERNELWAKELOCKPULLER_H +#pragma once #include <utils/String16.h> -#include "external/StatsPuller.h" +#include "StatsPuller.h" namespace android { namespace os { @@ -29,11 +28,9 @@ public: // a number of stats need to be pulled from StatsCompanionService // const static int PULL_CODE_KERNEL_WAKELOCKS; - vector<StatsLogEventWrapper> pull() override; + vector<StatsLogEventWrapper> Pull() override; }; } // namespace statsd } // namespace os } // namespace android - -#endif // STATSD_KERNELWAKELOCKPULLER_H diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h new file mode 100644 index 000000000000..0d505cb49e8f --- /dev/null +++ b/cmds/statsd/src/external/PullDataReceiver.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 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 <utils/String16.h> +#include <unordered_map> +#include <utils/RefBase.h> +#include "StatsPuller.h" +#include "logd/LogEvent.h" + +namespace android { +namespace os { +namespace statsd { + +class PullDataReceiver : virtual public RefBase{ + public: + virtual ~PullDataReceiver() {} + virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) = 0; +}; + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index 66556291e976..774e7f093087 100644 --- a/cmds/statsd/src/external/StatsPuller.h +++ b/cmds/statsd/src/external/StatsPuller.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef STATSD_STATSPULLER_H -#define STATSD_STATSPULLER_H +#pragma once #include <android/os/StatsLogEventWrapper.h> #include <utils/String16.h> @@ -32,11 +31,9 @@ class StatsPuller { public: virtual ~StatsPuller(){}; - virtual vector<StatsLogEventWrapper> pull() = 0; + virtual vector<StatsLogEventWrapper> Pull() = 0; }; } // namespace statsd } // namespace os } // namespace android - -#endif // STATSD_STATSPULLER_H diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 7f554d3e398e..f45cb1ccaa74 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -18,44 +18,58 @@ #include "Log.h" #include <android/os/IStatsCompanionService.h> +#include <cutils/log.h> +#include <algorithm> +#include <climits> #include "KernelWakelockPuller.h" +#include "StatsPullerManager.h" #include "StatsService.h" -#include "external/StatsPullerManager.h" #include "logd/LogEvent.h" -#include <cutils/log.h> -#include <algorithm> #include <iostream> -using namespace android; +using std::string; +using std::vector; namespace android { namespace os { namespace statsd { -const int StatsPullerManager::KERNEL_WAKELOCKS = 1; +const int kernel_wakelock = 1; +const unordered_map<string, int> StatsPullerManager::kPullCodes({{"KERNEL_WAKELOCK", + kernel_wakelock}}); -StatsPullerManager::StatsPullerManager() { - mStatsPullers.insert( - {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()}); +StatsPullerManager::StatsPullerManager() + : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) { + mPullers.insert({kernel_wakelock, make_unique<KernelWakelockPuller>()}); + mStatsCompanionService = get_stats_companion_service(); + if (mStatsCompanionService != nullptr) { + mStatsCompanionService->cancelPullingAlarms(); + } else { + VLOG("Failed to update pulling interval"); + } } -vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) { +static const int log_msg_header_size = 28; + +vector<shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode, uint64_t timestampSec) { if (DEBUG) ALOGD("Initiating pulling %d", pullCode); - vector<std::shared_ptr<LogEvent>> ret; - if (mStatsPullers.find(pullCode) != mStatsPullers.end()) { - vector<StatsLogEventWrapper> outputs = (mStatsPullers.find(pullCode)->second)->pull(); + vector<shared_ptr<LogEvent>> ret; + auto itr = mPullers.find(pullCode); + if (itr != mPullers.end()) { + vector<StatsLogEventWrapper> outputs = itr->second->Pull(); for (const StatsLogEventWrapper& it : outputs) { log_msg tmp; + tmp.entry_v1.sec = timestampSec; + tmp.entry_v1.nsec = 0; tmp.entry_v1.len = it.bytes.size(); // Manually set the header size to 28 bytes to match the pushed log events. - tmp.entry.hdr_size = 28; + tmp.entry.hdr_size = log_msg_header_size; // And set the received bytes starting after the 28 bytes reserved for header. - std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + 28); - std::shared_ptr<LogEvent> evt = std::make_shared<LogEvent>(tmp); + copy(it.bytes.begin(), it.bytes.end(), tmp.buf + log_msg_header_size); + shared_ptr<LogEvent> evt = make_shared<LogEvent>(tmp); ret.push_back(evt); - // ret.emplace_back(tmp); } return ret; } else { @@ -64,6 +78,112 @@ vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) { } } +sp<IStatsCompanionService> StatsPullerManager::get_stats_companion_service() { + sp<IStatsCompanionService> statsCompanion = nullptr; + // Get statscompanion service from service manager + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != nullptr) { + const String16 name("statscompanion"); + statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name)); + if (statsCompanion == nullptr) { + ALOGW("statscompanion service unavailable!"); + return nullptr; + } + } + return statsCompanion; +} + +StatsPullerManager& StatsPullerManager::GetInstance() { + static StatsPullerManager instance; + return instance; +} + +int StatsPullerManager::GetPullCode(string atomName) { + if (kPullCodes.find(atomName) != kPullCodes.end()) { + return kPullCodes.find(atomName)->second; + } else { + return -1; + } +} + +long StatsPullerManager::get_pull_start_time_ms() { + // TODO: limit and align pull intervals to 10min boundaries if this turns out to be a problem + return time(nullptr) * 1000; +} + +void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs) { + AutoMutex _l(mReceiversLock); + vector<ReceiverInfo>& receivers = mReceivers[pullCode]; + for (auto it = receivers.begin(); it != receivers.end(); it++) { + if (it->receiver.get() == receiver.get()) { + VLOG("Receiver already registered of %d", (int)receivers.size()); + return; + } + } + ReceiverInfo receiverInfo; + receiverInfo.receiver = receiver; + receiverInfo.timeInfo.first = intervalMs; + receivers.push_back(receiverInfo); + + // There is only one alarm for all pulled events. So only set it to the smallest denom. + if (intervalMs < mCurrentPullingInterval) { + VLOG("Updating pulling interval %ld", intervalMs); + mCurrentPullingInterval = intervalMs; + if (mStatsCompanionService != nullptr) { + mStatsCompanionService->setPullingAlarms(mPullStartTimeMs, mCurrentPullingInterval); + } else { + VLOG("Failed to update pulling interval"); + } + } + VLOG("Puller for pullcode %d registered of %d", pullCode, (int)receivers.size()); +} + +void StatsPullerManager::UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver) { + AutoMutex _l(mReceiversLock); + if (mReceivers.find(pullCode) == mReceivers.end()) { + VLOG("Unknown pull code or no receivers: %d", pullCode); + return; + } + auto& receivers = mReceivers.find(pullCode)->second; + for (auto it = receivers.begin(); it != receivers.end(); it++) { + if (receiver.get() == it->receiver.get()) { + receivers.erase(it); + VLOG("Puller for pullcode %d unregistered of %d", pullCode, (int)receivers.size()); + return; + } + } +} + +void StatsPullerManager::OnAlarmFired() { + AutoMutex _l(mReceiversLock); + + uint64_t currentTimeMs = time(nullptr) * 1000; + + vector<pair<int, vector<ReceiverInfo*>>> needToPull = + vector<pair<int, vector<ReceiverInfo*>>>(); + for (auto& pair : mReceivers) { + vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>(); + if (pair.second.size() != 0){ + for(auto& receiverInfo : pair.second) { + if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) { + receivers.push_back(&receiverInfo); + } + } + if (receivers.size() > 0) { + needToPull.push_back(make_pair(pair.first, receivers)); + } + } + } + + for (const auto& pullInfo : needToPull) { + const vector<shared_ptr<LogEvent>>& data = Pull(pullInfo.first, currentTimeMs/1000); + for(const auto& receiverInfo : pullInfo.second) { + receiverInfo->receiver->onDataPulled(data); + receiverInfo->timeInfo.second = currentTimeMs; + } + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index e46aec1c060b..e599b6904ed4 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -14,38 +14,79 @@ * limitations under the License. */ -#ifndef STATSD_STATSPULLERMANAGER_H -#define STATSD_STATSPULLERMANAGER_H +#pragma once +#include <android/os/IStatsCompanionService.h> +#include <binder/IServiceManager.h> +#include <utils/RefBase.h> #include <utils/String16.h> +#include <utils/String8.h> +#include <utils/threads.h> +#include <string> #include <unordered_map> -#include "external/StatsPuller.h" +#include <vector> +#include "PullDataReceiver.h" +#include "StatsPuller.h" #include "logd/LogEvent.h" -#include "matchers/matcher_util.h" namespace android { namespace os { namespace statsd { -const static int KERNEL_WAKELOCKS = 1; - class StatsPullerManager : public virtual RefBase { public: - // Enums of pulled data types (pullCodes) - // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java. - // TODO: pull the constant from stats_events.proto instead - const static int KERNEL_WAKELOCKS; - StatsPullerManager(); + static StatsPullerManager& GetInstance(); + + void RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs); + + void UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver); // We return a vector of shared_ptr since LogEvent's copy constructor is not available. - vector<std::shared_ptr<LogEvent>> Pull(const int pullCode); + vector<std::shared_ptr<LogEvent>> Pull(const int pullCode, const uint64_t timestampSec); + + // Translate metric name to pullCodes. + // return -1 if no valid pullCode is found + int GetPullCode(std::string metricName); + + void OnAlarmFired(); private: - std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers; + StatsPullerManager(); + + sp<IStatsCompanionService> mStatsCompanionService = nullptr; + + sp<IStatsCompanionService> get_stats_companion_service(); + + std::unordered_map<int, std::unique_ptr<StatsPuller>> mPullers; + + + + // internal state of a bucket. + typedef struct { + // pull_interval_sec : last_pull_time_sec + std::pair<uint64_t, uint64_t> timeInfo; + sp<PullDataReceiver> receiver; + } ReceiverInfo; + + std::map<int, std::vector<ReceiverInfo>> mReceivers; + + Mutex mReceiversLock; + + long mCurrentPullingInterval; + + // for value metrics, it is important for the buckets to be aligned to multiple of smallest + // bucket size. All pulled metrics start pulling based on this time, so that they can be + // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the + // request time. + const long mPullStartTimeMs; + + long get_pull_start_time_ms(); + + LogEvent parse_pulled_data(String16 data); + + static const std::unordered_map<std::string, int> kPullCodes; }; } // namespace statsd } // namespace os -} // namespace android - -#endif // STATSD_STATSPULLERMANAGER_H +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 1a039f6d61c5..451d26df28e0 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define DEBUG true // STOPSHIP if true #include "logd/LogEvent.h" #include <sstream> diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 10816f6206aa..9f8558d59baf 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -135,7 +135,7 @@ void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint void CountMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, - const LogEvent& event) { + const LogEvent& event, bool scheduledPull) { uint64_t eventTimeNs = event.GetTimestampNs(); flushCounterIfNeeded(eventTimeNs); diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 5d1889a9b18f..80e80d95d801 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -59,7 +59,8 @@ public: protected: void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, - bool condition, const LogEvent& event) override; + bool condition, const LogEvent& event, + bool scheduledPull) override; private: const CountMetric mMetric; diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index dfed27576165..340f503fd651 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -168,7 +168,7 @@ void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) { void DurationMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKeys, bool condition, - const LogEvent& event) { + const LogEvent& event, bool scheduledPull) { flushIfNeeded(event.GetTimestampNs()); if (matcherIndex == mStopAllIndex) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 5b302b45dd0a..febf25d45cc2 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -62,7 +62,8 @@ public: protected: void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKeys, - bool condition, const LogEvent& event) override; + bool condition, const LogEvent& event, + bool scheduledPull) override; private: const DurationMetric mMetric; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index dd23d66da7cc..d71417936bfd 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -112,7 +112,7 @@ void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint void EventMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition, - const LogEvent& event) { + const LogEvent& event, bool scheduledPull) { if (!condition) { return; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index 72df0a77101b..7dd0e38a0533 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -41,7 +41,7 @@ public: void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, - bool condition, const LogEvent& event) override; + bool condition, const LogEvent& event, bool scheduledPull) override; void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override; diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index 3c8ce6e7dd1c..535f4a276fe1 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -21,7 +21,8 @@ namespace statsd { using std::map; -void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) { +void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, + bool scheduledPull) { uint64_t eventTimeNs = event.GetTimestampNs(); // this is old event, maybe statsd restarted? if (eventTimeNs < mStartTimeNs) { @@ -59,7 +60,8 @@ void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent condition = mCondition; } - onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event); + onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event, + scheduledPull); } } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 2083695e7238..3b117ec4e307 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -48,7 +48,7 @@ public: virtual ~MetricProducer(){}; // Consume the parsed stats log entry that already matched the "what" of the metric. - void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event); + void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, bool scheduledPull); virtual void onConditionChanged(const bool condition, const uint64_t eventTime) = 0; @@ -107,7 +107,7 @@ protected: virtual void onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition, - const LogEvent& event) = 0; + const LogEvent& event, bool scheduledPull) = 0; }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index d1df8aa75177..521fcc33ac47 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -145,7 +145,8 @@ void MetricsManager::onLogEvent(const LogEvent& event) { if (pair != mTrackerToMetricMap.end()) { auto& metricList = pair->second; for (const int metricIndex : metricList) { - mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event); + // pushed metrics are never scheduled pulls + mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event, false); } } } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp new file mode 100644 index 000000000000..cb6166dafa3a --- /dev/null +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2017 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 "ValueMetricProducer.h" + +#include <cutils/log.h> +#include <limits.h> +#include <stdlib.h> + +using std::map; +using std::unordered_map; +using std::list; +using std::make_shared; +using std::shared_ptr; +using std::unique_ptr; + +namespace android { +namespace os { +namespace statsd { + +// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently +ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex, + const sp<ConditionWizard>& wizard) + : MetricProducer((time(nullptr) / 600 * 600 * NANO_SECONDS_IN_A_SECOND), conditionIndex, + wizard), + mMetric(metric), + mPullCode(mStatsPullerManager.GetPullCode(mMetric.what())) { + // TODO: valuemetric for pushed events may need unlimited bucket length + mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000; + + mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end()); + + if (metric.links().size() > 0) { + mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(), + metric.links().end()); + mConditionSliced = true; + } + + if (!metric.has_condition() && mPullCode != -1) { + mStatsPullerManager.RegisterReceiver(mPullCode, this, metric.bucket().bucket_size_millis()); + } + + VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(), + (long long)mBucketSizeNs, (long long)mStartTimeNs); +} + +ValueMetricProducer::~ValueMetricProducer() { + VLOG("~ValueMetricProducer() called"); +} + +void ValueMetricProducer::finish() { + // TODO: write the StatsLogReport to dropbox using + // DropboxWriter. +} + +static void addSlicedCounterToReport(StatsLogReport_ValueMetricDataWrapper& wrapper, + const vector<KeyValuePair>& key, + const vector<ValueBucketInfo>& buckets) { + ValueMetricData* data = wrapper.add_data(); + for (const auto& kv : key) { + data->add_dimension()->CopyFrom(kv); + } + for (const auto& bucket : buckets) { + data->add_bucket_info()->CopyFrom(bucket); + VLOG("\t bucket [%lld - %lld] value: %lld", bucket.start_bucket_nanos(), + bucket.end_bucket_nanos(), bucket.value()); + } +} + +void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { + VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id()); +} + +StatsLogReport ValueMetricProducer::onDumpReport() { + VLOG("metric %lld dump report now...", mMetric.metric_id()); + + StatsLogReport report; + report.set_metric_id(mMetric.metric_id()); + report.set_start_report_nanos(mStartTimeNs); + + // Dump current bucket if it's stale. + // If current bucket is still on-going, don't force dump current bucket. + // In finish(), We can force dump current bucket. + // flush_if_needed(time(nullptr) * NANO_SECONDS_IN_A_SECOND); + report.set_end_report_nanos(mCurrentBucketStartTimeNs); + + StatsLogReport_ValueMetricDataWrapper* wrapper = report.mutable_value_metrics(); + + for (const auto& pair : mPastBuckets) { + const HashableDimensionKey& hashableKey = pair.first; + auto it = mDimensionKeyMap.find(hashableKey); + if (it == mDimensionKeyMap.end()) { + ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str()); + continue; + } + + VLOG(" dimension key %s", hashableKey.c_str()); + addSlicedCounterToReport(*wrapper, it->second, pair.second); + } + return report; + // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped. +} + +void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) { + mCondition = condition; + + if (mPullCode != -1) { + vector<shared_ptr<LogEvent>> allData = mStatsPullerManager.Pull(mPullCode, eventTime); + if (mCondition == true) { + mStatsPullerManager.RegisterReceiver(mPullCode, this, + mMetric.bucket().bucket_size_millis()); + } else if (mCondition == ConditionState::kFalse) { + mStatsPullerManager.UnRegisterReceiver(mPullCode, this); + } + if (allData.size() == 0) { + return; + } + AutoMutex _l(mLock); + if (allData.size() == 0) { + return; + } + for (const auto& data : allData) { + onMatchedLogEvent(0, *data, false); + } + flush_if_needed(eventTime); + } + return; +} + +void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) { + if (mCondition == ConditionState::kTrue || !mMetric.has_condition()) { + AutoMutex _l(mLock); + if (allData.size() == 0) { + return; + } + uint64_t eventTime = allData.at(0)->GetTimestampNs(); + for (const auto& data : allData) { + onMatchedLogEvent(0, *data, true); + } + flush_if_needed(eventTime); + } +} + +void ValueMetricProducer::onMatchedLogEventInternal( + const size_t matcherIndex, const HashableDimensionKey& eventKey, + const map<string, HashableDimensionKey>& conditionKey, bool condition, + const LogEvent& event, bool scheduledPull) { + uint64_t eventTimeNs = event.GetTimestampNs(); + if (eventTimeNs < mCurrentBucketStartTimeNs) { + VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, + (long long)mCurrentBucketStartTimeNs); + return; + } + + Interval& interval = mCurrentSlicedBucket[eventKey]; + + long value = get_value(event); + + if (scheduledPull) { + if (interval.raw.size() > 0) { + interval.raw.back().second = value; + } else { + interval.raw.push_back(std::make_pair(value, value)); + } + mNextSlicedBucket[eventKey].raw[0].first = value; + } else { + if (mCondition == ConditionState::kTrue) { + interval.raw.push_back(std::make_pair(value, 0)); + } else { + if (interval.raw.size() != 0) { + interval.raw.back().second = value; + } + } + } + if (mPullCode == -1) { + flush_if_needed(eventTimeNs); + } +} + +long ValueMetricProducer::get_value(const LogEvent& event) { + status_t err = NO_ERROR; + long val = event.GetLong(mMetric.value_field(), &err); + if (err == NO_ERROR) { + return val; + } else { + VLOG("Can't find value in message."); + return 0; + } +} + +void ValueMetricProducer::flush_if_needed(const uint64_t eventTimeNs) { + if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) { + VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs, + (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs)); + return; + } + + VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs, + (int)mCurrentSlicedBucket.size()); + ValueBucketInfo info; + info.set_start_bucket_nanos(mCurrentBucketStartTimeNs); + info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs); + + for (const auto& slice : mCurrentSlicedBucket) { + long value = 0; + for (const auto& pair : slice.second.raw) { + value += pair.second - pair.first; + } + info.set_value(value); + VLOG(" %s, %ld", slice.first.c_str(), value); + // it will auto create new vector of ValuebucketInfo if the key is not found. + auto& bucketList = mPastBuckets[slice.first]; + bucketList.push_back(info); + } + + // Reset counters + mCurrentSlicedBucket.swap(mNextSlicedBucket); + mNextSlicedBucket.clear(); + int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs; + if (numBucketsForward >1) { + VLOG("Skipping forward %lld buckets", (long long)numBucketsForward); + } + mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs; + VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(), + (long long)mCurrentBucketStartTimeNs); +} + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h new file mode 100644 index 000000000000..4f1791351f87 --- /dev/null +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 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 <utils/threads.h> +#include <list> +#include "../condition/ConditionTracker.h" +#include "../external/PullDataReceiver.h" +#include "../external/StatsPullerManager.h" +#include "CountAnomalyTracker.h" +#include "MetricProducer.h" +#include "frameworks/base/cmds/statsd/src/stats_log.pb.h" +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" + +namespace android { +namespace os { +namespace statsd { + +class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { +public: + ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex, + const sp<ConditionWizard>& wizard); + + virtual ~ValueMetricProducer(); + + void onConditionChanged(const bool condition, const uint64_t eventTime) override; + + void finish() override; + + StatsLogReport onDumpReport() override; + + void onSlicedConditionMayChange(const uint64_t eventTime); + + void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override; + // TODO: Implement this later. + size_t byteSize() override{return 0;}; + + // TODO: Implement this later. + virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{}; + // TODO: Implement this later. + virtual void notifyAppRemoved(const string& apk, const int uid) override{}; + +protected: + void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, + const std::map<std::string, HashableDimensionKey>& conditionKey, + bool condition, const LogEvent& event, + bool scheduledPull) override; + +private: + const ValueMetric mMetric; + + StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance(); + + Mutex mLock; + + const int mPullCode; + + // internal state of a bucket. + typedef struct { + std::vector<std::pair<long, long>> raw; + } Interval; + + std::unordered_map<HashableDimensionKey, Interval> mCurrentSlicedBucket; + // If condition is true and pulling on schedule, the previous bucket value needs to be carried + // over to the next bucket. + std::unordered_map<HashableDimensionKey, Interval> mNextSlicedBucket; + + // Save the past buckets and we can clear when the StatsLogReport is dumped. + std::unordered_map<HashableDimensionKey, std::vector<ValueBucketInfo>> mPastBuckets; + + long get_value(const LogEvent& event); + + void flush_if_needed(const uint64_t eventTimeNs); +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 3b3ffb7aad6a..3d4036e8d176 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -16,11 +16,13 @@ #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 "ValueMetricProducer.h" #include "stats_util.h" using std::set; @@ -192,6 +194,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() + config.event_metric_size(); allMetricProducers.reserve(allMetricsCount); + StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance(); // Build MetricProducers for each metric defined in config. // (1) build CountMetricProducer @@ -307,6 +310,34 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l allMetricProducers.push_back(eventMetric); } + // value metrics + for (int i = 0; i < config.value_metric_size(); i++) { + const ValueMetric& metric = config.value_metric(i); + if (!metric.has_what()) { + ALOGW("cannot find what in ValueMetric %lld", metric.metric_id()); + return false; + } + + int pullCode = statsPullerManager.GetPullCode(metric.what()); + if (pullCode == -1) { + ALOGW("cannot find %s in pulled metrics", metric.what().c_str()); + return false; + } + + sp<MetricProducer> valueProducer; + auto condition_it = conditionTrackerMap.find(metric.condition()); + if (condition_it == conditionTrackerMap.end()) { + ALOGW("cannot find the Condition %s in the config", metric.condition().c_str()); + return false; + } + int metricIndex = allMetricProducers.size(); + valueProducer = new ValueMetricProducer(metric, condition_it->second, wizard); + // will create new vector if not exist before. + auto& metricList = conditionToMetricMap[condition_it->second]; + metricList.push_back(metricIndex); + + allMetricProducers.push_back(valueProducer); + } return true; } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index c91b7fc32a85..e089d0653238 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -21,6 +21,7 @@ #include <vector> #include "../condition/ConditionTracker.h" +#include "../external/StatsPullerManager.h" #include "../matchers/LogMatchingTracker.h" namespace android { diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto index 3789baf71705..5ce7c70ba20d 100644 --- a/cmds/statsd/src/stats_events.proto +++ b/cmds/statsd/src/stats_events.proto @@ -70,6 +70,7 @@ message StatsEvent { WifiScanStateChanged wifi_scan_state_changed = 39; PhoneSignalStrengthChanged phone_signal_strength_changed = 40; SettingChanged setting_changed = 41; + KernelWakelockPulled kernel_wakelock_pulled = 42; // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } } @@ -679,3 +680,16 @@ message SettingChanged { // The user ID associated. Defined in android/os/UserHandle.java optional int32 user = 7; } + +/* + * Pulls kernel wakelock changes. + * + * Pulled from: + * frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java + */ +message KernelWakelockPulled { + optional int32 count = 1; + optional int32 version = 2; + optional int64 total_time = 3; + optional string name = 4; +} diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto index 5e8ef245119a..9470372005f8 100644 --- a/cmds/statsd/src/stats_events_copy.proto +++ b/cmds/statsd/src/stats_events_copy.proto @@ -40,9 +40,28 @@ option java_outer_classname = "StatsEventProto"; */ message StatsEvent { oneof event { - ScreenStateChanged screen_state_changed = 1; - ProcessStateChanged process_state_changed = 2; - WakeLockChanged wakelock_changed = 3; + // For StatsLog reasons, 1 is illegal and will not work. Must start at 2. + BleScanStateChanged ble_scan_state_changed = 2; + BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3; + BleScanResultReceived ble_scan_result_received = 4; + SensorStateChanged sensor_state_changed = 5; + GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested + SyncStateChanged sync_state_changed = 7; + ScheduledJobStateChanged scheduled_job_state_changed = 8; + ScreenBrightnessChanged screen_brightness_changed = 9; + // 10-20 are temporarily reserved for wakelocks etc. + UidWakelockStateChanged uid_wakelock_state_changed = 11; + LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 12; + BatterySaverModeStateChanged battery_saver_mode_state_changed = 21; + DeviceIdleModeStateChanged device_idle_mode_state_changed = 22; + AudioStateChanged audio_state_changed = 23; + MediaCodecActivityChanged media_codec_activity_changed = 24; + CameraStateChanged camera_state_changed = 25; + FlashlightStateChanged flashlight_state_changed = 26; + UidProcessStateChanged uid_process_state_changed = 27; + ProcessLifeCycleStateChanged process_life_cycle_state_changed = 28; + ScreenStateChanged screen_state_changed = 29; + // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } } @@ -76,7 +95,7 @@ message WorkSource { * and those UIDs will be translated in xxx to those strings. * * CONVENTIONS: - * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange + * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange. * - If there is a UID, it goes first. Think in an object-oriented fashion. * ***************************************************************************** */ @@ -102,33 +121,347 @@ message ScreenStateChanged { } /** - * Logs that the state of a process state, as per the activity manager has changed. + * Logs that the state of a process state, as per the activity manager, has changed. * * Logged from: * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java */ -message ProcessStateChanged { - // TODO: Use the real (mapped) process states. +message UidProcessStateChanged { optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation // The state. + // TODO: Use the real (mapped) process states. optional int32 state = 2; } /** - * Logs that the state of a wakelock has changed. + * Logs that a process started, finished, crashed, or ANRed. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java + */ +message ProcessLifeCycleStateChanged { + // TODO: Use the real (mapped) process states. + optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation + + // TODO: What is this? + optional string name = 2; + + // The state. + // TODO: Use an enum. + optional int32 event = 3; +} + + + +/** + * Logs when the ble scan state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message BleScanStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs when an unoptimized ble scan state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats). +message BleUnoptimizedScanStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs reporting of a ble scan finding results. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats). +message BleScanResultReceived { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + // Number of ble scan results returned. + optional int32 num_of_results = 2; +} + +/** + * Logs when a sensor state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message SensorStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + // TODO: Is there a way to get the actual name of the sensor? + // The id (int) of the sensor. + optional int32 sensor_id = 2; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 3; +} + + +/** + * Logs when GPS state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message GpsScanStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + + +/** + * Logs when a sync manager sync state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message SyncStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + // Name of the sync (as named in the app) + optional string name = 2; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 3; +} + +/** + * Logs when a job scheduler job state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message ScheduledJobStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + // Name of the job (as named in the app) + optional string name = 2; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 3; + + // TODO: Consider adding the stopReason (int) +} + +/** + * Logs when the audio state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message AudioStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs when the video codec state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message MediaCodecActivityChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs when the flashlight state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message FlashlightStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs when the camera state changes. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message CameraStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** + * Logs that the state of a wakelock (per app and per wakelock name) has changed. * * Logged from: * TODO */ -message WakeLockChanged { +message WakelockChanged { // TODO: Add attribution instead of uid. optional int32 uid = 1; + // Type of wakelock. + enum Type { + PARTIAL = 0; + FULL = 1; + WINDOW = 2; + } + optional int32 type = 2; + + // The wakelock tag (Called tag in the Java API, sometimes name elsewhere). + optional string tag = 3; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 4; +} + +/** + * Logs when an app is holding a wakelock, regardless of the wakelock's name. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message UidWakelockStateChanged { + // TODO: Add attribution instead of uid. + optional int32 uid = 1; + + // Type of wakelock. + enum Type { + PARTIAL = 0; + FULL = 1; + WINDOW = 2; + } + optional int32 type = 2; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 3; +} + +/** + * Logs when a partial wakelock is considered 'long' (over 1 min). + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message LongPartialWakelockStateChanged { + // TODO: Add attribution instead of uid? + optional int32 uid = 1; + // The wakelock tag (Called tag in the Java API, sometimes name elsewhere). optional string tag = 2; - // TODO: Use a constant instead of boolean? - optional bool state = 3; + // TODO: I have no idea what this is. + optional string history_tag = 3; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 4; +} + +/** + * Logs Battery Saver state change. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message BatterySaverModeStateChanged { + enum State { + OFF = 0; + ON = 1; + } + optional State state = 1; } +/** + * Logs Doze mode state change. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java + */ +message DeviceIdleModeStateChanged { + // TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_. + optional int32 state = 1; +} + +/** + * Logs screen brightness level. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java + */ +message ScreenBrightnessChanged { + // Screen brightness level. Should be in [-1, 255] according to PowerManager.java. + optional int32 level = 1; +}
\ No newline at end of file diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 66a31a5cd205..1e37ff8c0aef 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -143,9 +143,11 @@ message StatsLogReport { message ValueMetricDataWrapper { repeated ValueMetricData data = 1; } + message GaugeMetricDataWrapper { repeated GaugeMetricData data = 1; } + oneof data { EventMetricDataWrapper event_metrics = 4; CountMetricDataWrapper count_metrics = 5; diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp index 2af17c2d33c0..e8e4d8be1cd6 100644 --- a/cmds/statsd/tests/MetricsManager_test.cpp +++ b/cmds/statsd/tests/MetricsManager_test.cpp @@ -18,6 +18,7 @@ #include "src/matchers/LogMatchingTracker.h" #include "src/metrics/CountMetricProducer.h" #include "src/metrics/MetricProducer.h" +#include "src/metrics/ValueMetricProducer.h" #include "src/metrics/metrics_manager_util.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index 20f6c8ecd495..c0a95cc08dec 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -46,10 +46,10 @@ interface IStatsCompanionService { * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately, * and alarm is inexact. */ - oneway void setPollingAlarms(long timestampMs, long intervalMs); + oneway void setPullingAlarms(long timestampMs, long intervalMs); /** Cancel any repeating polling alarm. */ - oneway void cancelPollingAlarms(); + oneway void cancelPullingAlarms(); /** Pull the specified data. Results will be sent to statsd when complete. */ StatsLogEventWrapper[] pullData(int pullCode); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 2219de8d898f..f50939fb422d 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -65,7 +65,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static final Object sStatsdLock = new Object(); private final PendingIntent mAnomalyAlarmIntent; - private final PendingIntent mPollingAlarmIntent; + private final PendingIntent mPullingAlarmIntent; private final BroadcastReceiver mAppUpdateReceiver; private final BroadcastReceiver mUserUpdateReceiver; @@ -76,8 +76,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mContext, AnomalyAlarmReceiver.class), 0); - mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0, - new Intent(mContext, PollingAlarmReceiver.class), 0); + mPullingAlarmIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0); mAppUpdateReceiver = new AppUpdateReceiver(); mUserUpdateReceiver = new BroadcastReceiver() { @Override @@ -206,24 +206,25 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - public final static class PollingAlarmReceiver 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 polling alarm firing"); - return; - } - try { - // Two-way call to statsd to retain AlarmManager wakelock - sStatsd.informPollAlarmFired(); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to inform statsd of polling alarm firing", e); - } - } - // AlarmManager releases its own wakelock here. + public final static class PullingAlarmReceiver 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 pulling alarm firing"); + return; + } + try { + // Two-way call to statsd to retain AlarmManager wakelock + sStatsd.informPollAlarmFired(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to inform statsd of pulling alarm firing", e); + } } + // AlarmManager releases its own wakelock here. + } } @Override // Binder call @@ -254,32 +255,32 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void setPollingAlarms(long timestampMs, long intervalMs) { - enforceCallingPermission(); - if (DEBUG) Slog.d(TAG, "Setting polling alarm for " + timestampMs - + " every " + intervalMs + "ms"); - final long callingToken = Binder.clearCallingIdentity(); - try { - // using RTC, not RTC_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. - // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? - mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, - mPollingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void setPullingAlarms(long timestampMs, long intervalMs) { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms"); + final long callingToken = Binder.clearCallingIdentity(); + try { + // using RTC, not RTC_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. + // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? + mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } @Override // Binder call - public void cancelPollingAlarms() { - enforceCallingPermission(); - if (DEBUG) Slog.d(TAG, "Cancelling polling alarm"); - final long callingToken = Binder.clearCallingIdentity(); - try { - mAlarmManager.cancel(mPollingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void cancelPullingAlarms() { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Cancelling pulling alarm"); + final long callingToken = Binder.clearCallingIdentity(); + try { + mAlarmManager.cancel(mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } // These values must be kept in sync with cmd/statsd/StatsPullerManager.h. @@ -304,7 +305,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { String name = ent.getKey(); KernelWakelockStats.Entry kws = ent.getValue(); - StatsLogEventWrapper e = new StatsLogEventWrapper(101, 4); + StatsLogEventWrapper e = new StatsLogEventWrapper(41, 4); e.writeInt(kws.mCount); e.writeInt(kws.mVersion); e.writeLong(kws.mTotalTime); @@ -441,7 +442,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mContext.unregisterReceiver(mAppUpdateReceiver); mContext.unregisterReceiver(mUserUpdateReceiver); cancelAnomalyAlarm(); - cancelPollingAlarms(); + cancelPullingAlarms(); } } |