reretry ValueMetric implementation and pulling mechanism
Note:
This is for value metric. The default operations is sum the diffs.
The test uses kernel wake lock, which also needs dimension by kernel
wake lock name.
The test is a bit cumbersome as it needs StatsCompanionService to do
the alarm, which is not exact alarm.
The internal state of a slice of bucket would look something like this:
4:ipc0000005e_727_android.hardwar
0 0
4:SensorService_wakelock
40 64
4:ipc0000005c_727_android.hardwar
...
Test: manual test on device.
Change-Id: I2ed0ac7d3c5fcba8b7611d46f38a38ffd8bdc92a
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 58ba42f..54ade35 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
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 a856a27..edb1a0f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -65,7 +65,6 @@
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_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 @@
"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 7f04658..3930d31 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 @@
/**
* 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 e3ccb06..8812719 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -139,6 +139,9 @@
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 @@
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 ee072f8..521d3f6 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 @@
// 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 c12806c..cc8059d 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 @@
// 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 0000000..0d505cb
--- /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 6655629..774e7f0 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 @@
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 7f554d3..f45cb1c 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 "KernelWakelockPuller.h"
-#include "StatsService.h"
-#include "external/StatsPullerManager.h"
-#include "logd/LogEvent.h"
#include <cutils/log.h>
#include <algorithm>
+#include <climits>
+#include "KernelWakelockPuller.h"
+#include "StatsPullerManager.h"
+#include "StatsService.h"
+#include "logd/LogEvent.h"
#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 @@
}
}
+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 e46aec1..e599b69 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 1a039f6..451d26d 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 10816f6..9f8558d 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -135,7 +135,7 @@
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 5d1889a..80e80d9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -59,7 +59,8 @@
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 dfed275..340f503 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -168,7 +168,7 @@
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 5b302b4..febf25d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -62,7 +62,8 @@
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 dd23d66..d714179 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -112,7 +112,7 @@
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 72df0a7..7dd0e38 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -41,7 +41,7 @@
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 3c8ce6e..535f4a2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -21,7 +21,8 @@
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 @@
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 2083695..3b117ec 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -48,7 +48,7 @@
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 @@
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 d1df8aa..521fcc3 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -145,7 +145,8 @@
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 0000000..cb6166d
--- /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 0000000..4f17913
--- /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 3b3ffb7..3d4036e 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 @@
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 @@
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 c91b7fc..e089d065 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 3789baf..5ce7c70 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -70,6 +70,7 @@
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 @@
// 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 5e8ef24..9470372 100644
--- a/cmds/statsd/src/stats_events_copy.proto
+++ b/cmds/statsd/src/stats_events_copy.proto
@@ -40,9 +40,28 @@
*/
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 @@
* 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 @@
}
/**
- * 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 66a31a5..1e37ff8 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -143,9 +143,11 @@
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 2af17c2..e8e4d8b 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 20f6c8e..c0a95cc 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -46,10 +46,10 @@
* 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 2219de8..f50939f 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 @@
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 @@
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 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 @@
}
@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 @@
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 @@
mContext.unregisterReceiver(mAppUpdateReceiver);
mContext.unregisterReceiver(mUserUpdateReceiver);
cancelAnomalyAlarm();
- cancelPollingAlarms();
+ cancelPullingAlarms();
}
}