summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/incident_helper/src/ih_util.cpp149
-rw-r--r--cmds/incident_helper/src/ih_util.h30
-rw-r--r--cmds/incident_helper/src/main.cpp3
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp89
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.h35
-rw-r--r--cmds/incident_helper/testdata/system_properties.txt14
-rw-r--r--cmds/incident_helper/tests/SystemPropertiesParser_test.cpp95
-rw-r--r--cmds/sm/src/com/android/commands/sm/Sm.java12
-rw-r--r--cmds/statsd/Android.bp2
-rw-r--r--cmds/statsd/Android.mk2
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp90
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h24
-rw-r--r--cmds/statsd/src/StatsService.cpp192
-rw-r--r--cmds/statsd/src/StatsService.h33
-rw-r--r--cmds/statsd/src/atoms.proto (renamed from cmds/statsd/src/stats_events.proto)21
-rw-r--r--cmds/statsd/src/atoms_copy.proto910
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp19
-rw-r--r--cmds/statsd/src/condition/condition_util.cpp3
-rw-r--r--cmds/statsd/src/config/ConfigKey.h2
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp158
-rw-r--r--cmds/statsd/src/config/ConfigManager.h45
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp7
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidPuller.cpp7
-rw-r--r--cmds/statsd/src/external/ResourcePowerManagerPuller.cpp31
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp88
-rw-r--r--cmds/statsd/src/logd/LogEvent.h37
-rw-r--r--cmds/statsd/src/main.cpp2
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp19
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp24
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp8
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h25
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp39
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h5
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp43
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h9
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp33
-rw-r--r--cmds/statsd/src/packages/PackageInfoListener.h2
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp2
-rw-r--r--cmds/statsd/src/packages/UidMap.h2
-rw-r--r--cmds/statsd/src/stats_events_copy.proto479
-rw-r--r--cmds/statsd/src/stats_log.proto4
-rw-r--r--cmds/statsd/src/statsd_config.proto72
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp2
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp82
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp14
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp19
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp6
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp6
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp43
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp65
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp40
55 files changed, 2207 insertions, 949 deletions
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index 0b51e66c2108..db4f586c7e31 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -30,22 +30,26 @@ bool isValidChar(char c) {
|| (v == (uint8_t)'_');
}
-static std::string trim(const std::string& s, const std::string& chars) {
- const auto head = s.find_first_not_of(chars);
+std::string trim(const std::string& s, const std::string& charset) {
+ const auto head = s.find_first_not_of(charset);
if (head == std::string::npos) return "";
- const auto tail = s.find_last_not_of(chars);
+ const auto tail = s.find_last_not_of(charset);
return s.substr(head, tail - head + 1);
}
-static std::string trimDefault(const std::string& s) {
+static inline std::string toLowerStr(const std::string& s) {
+ std::string res(s);
+ std::transform(res.begin(), res.end(), res.begin(), ::tolower);
+ return res;
+}
+
+static inline std::string trimDefault(const std::string& s) {
return trim(s, DEFAULT_WHITESPACE);
}
-static std::string trimHeader(const std::string& s) {
- std::string res = trimDefault(s);
- std::transform(res.begin(), res.end(), res.begin(), ::tolower);
- return res;
+static inline std::string trimHeader(const std::string& s) {
+ return toLowerStr(trimDefault(s));
}
// This is similiar to Split in android-base/file.h, but it won't add empty string
@@ -188,97 +192,106 @@ bool Reader::ok(std::string* error) {
}
// ==============================================================================
-static int
-lookupName(const char** names, const int size, const char* name)
+Table::Table(const char* names[], const uint64_t ids[], const int count)
+ :mEnums(),
+ mEnumValuesByName()
{
- for (int i=0; i<size; i++) {
- if (strcmp(name, names[i]) == 0) {
- return i;
- }
+ map<std::string, uint64_t> fields;
+ for (int i = 0; i < count; i++) {
+ fields[names[i]] = ids[i];
}
- return -1;
-}
-
-EnumTypeMap::EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount)
- :mEnumNames(enumNames),
- mEnumValues(enumValues),
- mEnumCount(enumCount)
-{
-}
-
-EnumTypeMap::~EnumTypeMap()
-{
+ mFields = fields;
}
-int
-EnumTypeMap::parseValue(const std::string& value)
+Table::~Table()
{
- int index = lookupName(mEnumNames, mEnumCount, value.c_str());
- if (index < 0) return mEnumValues[0]; // Assume value 0 is default
- return mEnumValues[index];
}
-Table::Table(const char* names[], const uint64_t ids[], const int count)
- :mFieldNames(names),
- mFieldIds(ids),
- mFieldCount(count),
- mEnums()
+void
+Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize)
{
-}
+ if (mFields.find(field) == mFields.end()) return;
-Table::~Table()
-{
+ map<std::string, int> enu;
+ for (int i = 0; i < enumSize; i++) {
+ enu[enumNames[i]] = enumValues[i];
+ }
+ mEnums[field] = enu;
}
void
-Table::addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize)
+Table::addEnumNameToValue(const char* enumName, const int enumValue)
{
- int index = lookupName(mFieldNames, mFieldCount, field);
- if (index < 0) return;
-
- EnumTypeMap enu(enumNames, enumValues, enumSize);
- mEnums[index] = enu;
+ mEnumValuesByName[enumName] = enumValue;
}
bool
Table::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value)
{
- int index = lookupName(mFieldNames, mFieldCount, name.c_str());
- if (index < 0) return false;
+ if (mFields.find(name) == mFields.end()) return false;
- uint64_t found = mFieldIds[index];
- switch (found & FIELD_TYPE_MASK) {
- case FIELD_TYPE_DOUBLE:
- case FIELD_TYPE_FLOAT:
+ uint64_t found = mFields[name];
+ record_t repeats; // used for repeated fields
+ switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) {
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT:
proto->write(found, toDouble(value));
break;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_BYTES:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES:
proto->write(found, value);
break;
- case FIELD_TYPE_INT64:
- case FIELD_TYPE_SINT64:
- case FIELD_TYPE_UINT64:
- case FIELD_TYPE_FIXED64:
- case FIELD_TYPE_SFIXED64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64:
proto->write(found, toLongLong(value));
break;
- case FIELD_TYPE_BOOL:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL:
+ if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) {
+ proto->write(found, true);
+ break;
+ }
+ if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) {
+ proto->write(found, false);
+ break;
+ }
return false;
- case FIELD_TYPE_ENUM:
- if (mEnums.find(index) == mEnums.end()) {
- // forget to add enum type mapping
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM:
+ // if the field has its own enum mapping, use this, otherwise use general name to value mapping.
+ if (mEnums.find(name) != mEnums.end()) {
+ if (mEnums[name].find(value) != mEnums[name].end()) {
+ proto->write(found, mEnums[name][value]);
+ } else {
+ proto->write(found, 0); // TODO: should get the default enum value (Unknown)
+ }
+ } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) {
+ proto->write(found, mEnumValuesByName[value]);
+ } else {
return false;
}
- proto->write(found, mEnums[index].parseValue(value));
break;
- case FIELD_TYPE_INT32:
- case FIELD_TYPE_SINT32:
- case FIELD_TYPE_UINT32:
- case FIELD_TYPE_FIXED32:
- case FIELD_TYPE_SFIXED32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32:
proto->write(found, toInt(value));
break;
+ // REPEATED TYPE below:
+ case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32:
+ repeats = parseRecord(value, COMMA_DELIMITER);
+ for (size_t i=0; i<repeats.size(); i++) {
+ proto->write(found, toInt(repeats[i]));
+ }
+ break;
+ case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING:
+ repeats = parseRecord(value, COMMA_DELIMITER);
+ for (size_t i=0; i<repeats.size(); i++) {
+ proto->write(found, repeats[i]);
+ }
+ break;
default:
return false;
}
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index e8366fa599e2..4a5fe1dd7a42 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -37,6 +37,9 @@ const std::string COMMA_DELIMITER = ",";
// returns true if c is a-zA-Z0-9 or underscore _
bool isValidChar(char c);
+// trim the string with the given charset
+std::string trim(const std::string& s, const std::string& charset);
+
/**
* When a text has a table format like this
* line 1: HeadA HeadB HeadC
@@ -98,21 +101,6 @@ private:
std::string mStatus;
};
-class EnumTypeMap
-{
-public:
- EnumTypeMap() {};
- EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount);
- ~EnumTypeMap();
-
- int parseValue(const std::string& value);
-
-private:
- const char** mEnumNames;
- const uint32_t* mEnumValues;
- int mEnumCount;
-};
-
/**
* The class contains a mapping between table headers to its field ids.
* And allow users to insert the field values to proto based on its header name.
@@ -124,14 +112,16 @@ public:
~Table();
// Add enum names to values for parsing purpose.
- void addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize);
+ void addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize);
+
+ // manually add enum names to values mapping, useful when an Enum type is used by a lot of fields, and there are no name conflicts
+ void addEnumNameToValue(const char* enumName, const int enumValue);
bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
private:
- const char** mFieldNames;
- const uint64_t* mFieldIds;
- const int mFieldCount;
- map<int, EnumTypeMap> mEnums;
+ map<std::string, uint64_t> mFields;
+ map<std::string, map<std::string, int>> mEnums;
+ map<std::string, int> mEnumValuesByName;
};
#endif // INCIDENT_HELPER_UTIL_H
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index 5c9a468dea0b..c8a0883d493c 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -21,6 +21,7 @@
#include "parsers/KernelWakesParser.h"
#include "parsers/PageTypeInfoParser.h"
#include "parsers/ProcrankParser.h"
+#include "parsers/SystemPropertiesParser.h"
#include <android-base/file.h>
#include <getopt.h>
@@ -50,6 +51,8 @@ static TextParserBase* selectParser(int section) {
return new ReverseParser();
/* ========================================================================= */
// IDs larger than 1 are section ids reserved in incident.proto
+ case 1000:
+ return new SystemPropertiesParser();
case 2000:
return new ProcrankParser();
case 2001:
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
new file mode 100644
index 000000000000..ee5feb03242e
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/system_properties.proto.h"
+#include "ih_util.h"
+#include "SystemPropertiesParser.h"
+
+using namespace android::os;
+
+const string LINE_DELIMITER = "]: [";
+
+// system properties' names sometimes are not valid proto field names, make the names valid.
+static string convertToFieldName(const string& name) {
+ int len = (int)name.length();
+ char cstr[len + 1];
+ strcpy(cstr, name.c_str());
+ for (int i = 0; i < len; i++) {
+ if (!isValidChar(cstr[i])) {
+ cstr[i] = '_';
+ }
+ }
+ return string(cstr);
+}
+
+status_t
+SystemPropertiesParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ string name; // the name of the property
+ string value; // the string value of the property
+
+ ProtoOutputStream proto;
+ Table table(SystemPropertiesProto::_FIELD_NAMES, SystemPropertiesProto::_FIELD_IDS, SystemPropertiesProto::_FIELD_COUNT);
+ table.addEnumNameToValue("running", SystemPropertiesProto::STATUS_RUNNING);
+ table.addEnumNameToValue("stopped", SystemPropertiesProto::STATUS_STOPPED);
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ line = line.substr(1, line.size() - 2); // trim []
+ size_t index = line.find(LINE_DELIMITER); // split by "]: ["
+ if (index == string::npos) {
+ fprintf(stderr, "Bad Line %s\n", line.c_str());
+ continue;
+ }
+ name = line.substr(0, index);
+ value = trim(line.substr(index + 4), DEFAULT_WHITESPACE);
+ if (value.empty()) continue;
+
+ // if the property name couldn't be found in proto definition or the value has mistype,
+ // add to extra properties with its name and value
+ if (!table.insertField(&proto, convertToFieldName(name), value)) {
+ long long token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES);
+ proto.write(SystemPropertiesProto::Property::NAME, name);
+ proto.write(SystemPropertiesProto::Property::VALUE, value);
+ proto.end(token);
+ }
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.h b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
new file mode 100644
index 000000000000..c4016006a48a
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_PROPERTIES_PARSER_H
+#define SYSTEM_PROPERTIES_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * SystemProperties parser, parses text produced by command getprop.
+ */
+class SystemPropertiesParser : public TextParserBase {
+public:
+ SystemPropertiesParser() : TextParserBase(String8("SystemPropertiesParser")) {};
+ ~SystemPropertiesParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // SYSTEM_PROPERTIES_PARSER_H
diff --git a/cmds/incident_helper/testdata/system_properties.txt b/cmds/incident_helper/testdata/system_properties.txt
new file mode 100644
index 000000000000..57c07ee9d75e
--- /dev/null
+++ b/cmds/incident_helper/testdata/system_properties.txt
@@ -0,0 +1,14 @@
+[aaudio.hw_burst_min_usec]: [2000]
+[aaudio.mmap_exclusive_policy]: [2]
+[dalvik.vm.appimageformat]: [lz4]
+[gsm.operator.isroaming]: [false]
+[init.svc.vendor.imsqmidaemon]: [running]
+[init.svc.vendor.init-radio-sh]: [stopped]
+[net.dns1]: [2001:4860:4860::8844]
+[net.tcp.buffersize.wifi]: [524288,2097152,4194304,262144,524288,1048576]
+[nfc.initialized]: [True]
+[persist_radio_VT_ENABLE]: [1]
+[ro.boot.boottime]: [1BLL:85,1BLE:898,2BLL:0,2BLE:862,SW:6739,KL:340]
+[ro.bootimage.build.date.utc]: [1509394807]
+[ro.bootimage.build.fingerprint]: [google/marlin/marlin:P/MASTER/jinyithu10301320:eng/dev-keys]
+[ro.wifi.channels]: [] \ No newline at end of file
diff --git a/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
new file mode 100644
index 000000000000..23e292a512b9
--- /dev/null
+++ b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#include "SystemPropertiesParser.h"
+
+#include "frameworks/base/core/proto/android/os/system_properties.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class SystemPropertiesParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+ string getSerializedString(::google::protobuf::Message& message) {
+ string expectedStr;
+ message.SerializeToFileDescriptor(tf.fd);
+ ReadFileToString(tf.path, &expectedStr);
+ return expectedStr;
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(SystemPropertiesParserTest, HasSwapInfo) {
+ const string testFile = kTestDataPath + "system_properties.txt";
+ SystemPropertiesParser parser;
+ SystemPropertiesProto expected;
+
+ expected.set_aaudio_hw_burst_min_usec(2000);
+ expected.set_aaudio_mmap_exclusive_policy(2);
+ expected.set_dalvik_vm_appimageformat("lz4");
+ expected.set_gsm_operator_isroaming(false);
+ expected.set_init_svc_vendor_imsqmidaemon(SystemPropertiesProto_Status_STATUS_RUNNING);
+ expected.set_init_svc_vendor_init_radio_sh(SystemPropertiesProto_Status_STATUS_STOPPED);
+ expected.set_net_dns1("2001:4860:4860::8844");
+ expected.add_net_tcp_buffersize_wifi(524288);
+ expected.add_net_tcp_buffersize_wifi(2097152);
+ expected.add_net_tcp_buffersize_wifi(4194304);
+ expected.add_net_tcp_buffersize_wifi(262144);
+ expected.add_net_tcp_buffersize_wifi(524288);
+ expected.add_net_tcp_buffersize_wifi(1048576);
+ expected.set_nfc_initialized(true);
+ expected.set_persist_radio_vt_enable(1);
+ expected.add_ro_boot_boottime("1BLL:85");
+ expected.add_ro_boot_boottime("1BLE:898");
+ expected.add_ro_boot_boottime("2BLL:0");
+ expected.add_ro_boot_boottime("2BLE:862");
+ expected.add_ro_boot_boottime("SW:6739");
+ expected.add_ro_boot_boottime("KL:340");
+ expected.set_ro_bootimage_build_date_utc(1509394807LL);
+ expected.set_ro_bootimage_build_fingerprint("google/marlin/marlin:P/MASTER/jinyithu10301320:eng/dev-keys");
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 699de94a0240..77e8efafa2a0 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -101,6 +101,8 @@ public final class Sm {
runSetEmulateFbe();
} else if ("get-fbe-mode".equals(op)) {
runGetFbeMode();
+ } else if ("idle-maint".equals(op)) {
+ runIdleMaint();
} else if ("fstrim".equals(op)) {
runFstrim();
} else if ("set-virtual-disk".equals(op)) {
@@ -278,6 +280,15 @@ public final class Sm {
StorageManager.DEBUG_VIRTUAL_DISK);
}
+ public void runIdleMaint() throws RemoteException {
+ final boolean im_run = "run".equals(nextArg());
+ if (im_run) {
+ mSm.runIdleMaintenance();
+ } else {
+ mSm.abortIdleMaintenance();
+ }
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -300,6 +311,7 @@ public final class Sm {
System.err.println(" sm unmount VOLUME");
System.err.println(" sm format VOLUME");
System.err.println(" sm benchmark VOLUME");
+ System.err.println(" sm idle-maint [run|abort]");
System.err.println(" sm fstrim");
System.err.println("");
System.err.println(" sm forget [UUID|all]");
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 4ebca8430cf4..5fcb8a1a0892 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -20,7 +20,7 @@
cc_library_host_shared {
name: "libstats_proto_host",
srcs: [
- "src/stats_events.proto",
+ "src/atoms.proto",
],
shared_libs: [
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 0f6d868708bd..d8603636c7c0 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -20,7 +20,7 @@ statsd_common_src := \
../../core/java/android/os/IStatsManager.aidl \
src/stats_log.proto \
src/statsd_config.proto \
- src/stats_events_copy.proto \
+ src/atoms_copy.proto \
src/anomaly/AnomalyMonitor.cpp \
src/condition/CombinationConditionTracker.cpp \
src/condition/condition_util.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 8c70bb502174..abd2a35d76df 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -50,8 +50,8 @@ const int FIELD_ID_UID = 1;
const int FIELD_ID_NAME = 2;
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
- const std::function<void(const vector<uint8_t>&)>& pushLog)
- : mUidMap(uidMap), mPushLog(pushLog) {
+ const std::function<void(const ConfigKey&)>& sendBroadcast)
+ : mUidMap(uidMap), mSendBroadcast(sendBroadcast) {
}
StatsLogProcessor::~StatsLogProcessor() {
@@ -66,7 +66,7 @@ void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
}
// Hard-coded logic to update the isolated uid's in the uid-map.
- // The field numbers need to be currently updated by hand with stats_events.proto
+ // The field numbers need to be currently updated by hand with atoms.proto
if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) {
status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
bool is_create = msg.GetBool(3, &err);
@@ -102,12 +102,27 @@ void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig
}
}
-vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
+size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) {
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
- return vector<uint8_t>();
+ return 0;
}
+ return it->second->byteSize();
+}
+
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, vector<uint8_t>* outData) {
+ auto it = mMetricsManagers.find(key);
+ if (it == mMetricsManagers.end()) {
+ ALOGW("Config source %s does not exist", key.ToString().c_str());
+ return;
+ }
+
+ // This allows another broadcast to be sent within the rate-limit period if we get close to
+ // filling the buffer again soon.
+ mBroadcastTimesMutex.lock();
+ mLastBroadcastTimes.erase(key);
+ mBroadcastTimesMutex.unlock();
ProtoOutputStream proto;
@@ -131,17 +146,18 @@ vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize);
proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
- vector<uint8_t> buffer(proto.size());
- size_t pos = 0;
- auto iter = proto.data();
- while (iter.readBuffer() != NULL) {
- size_t toRead = iter.currentToRead();
- std::memcpy(&buffer[pos], iter.readBuffer(), toRead);
- pos += toRead;
- iter.rp()->move(toRead);
+ if (outData != nullptr) {
+ outData->clear();
+ outData->resize(proto.size());
+ size_t pos = 0;
+ auto iter = proto.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
}
-
- return buffer;
}
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
@@ -151,42 +167,34 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
}
- auto flushTime = mLastFlushTimes.find(key);
- if (flushTime != mLastFlushTimes.end()) {
- mLastFlushTimes.erase(flushTime);
- }
+
+ std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
+ mLastBroadcastTimes.erase(key);
}
void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
const ConfigKey& key,
const unique_ptr<MetricsManager>& metricsManager) {
- auto lastFlushNs = mLastFlushTimes.find(key);
- if (lastFlushNs != mLastFlushTimes.end()) {
- if (timestampNs - lastFlushNs->second < kMinFlushPeriod) {
- return;
- }
- }
+ std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
size_t totalBytes = metricsManager->byteSize();
- if (totalBytes > kMaxSerializedBytes) {
- flush();
- mLastFlushTimes[key] = std::move(timestampNs);
+ if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
+ auto lastFlushNs = mLastBroadcastTimes.find(key);
+ if (lastFlushNs != mLastBroadcastTimes.end()) {
+ if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) {
+ return;
+ }
+ }
+ mLastBroadcastTimes[key] = timestampNs;
+ ALOGD("StatsD requesting broadcast for %s", key.ToString().c_str());
+ mSendBroadcast(key);
+ } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
+ // We ignore the return value so we force each metric producer to clear its contents.
+ metricsManager->onDumpReport();
+ ALOGD("StatsD had to toss out metrics for %s", key.ToString().c_str());
}
}
-void StatsLogProcessor::flush() {
- // TODO: Take ConfigKey as an argument and flush metrics related to the
- // ConfigKey. Also, create a wrapper that holds a repeated field of
- // StatsLogReport's.
- /*
- StatsLogReport logReport;
- const int numBytes = logReport.ByteSize();
- vector<uint8_t> logReportBuffer(numBytes);
- logReport.SerializeToArray(&logReportBuffer[0], numBytes);
- mPushLog(logReportBuffer);
- */
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f38d71550eda..2091774b108e 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -33,7 +33,7 @@ namespace statsd {
class StatsLogProcessor : public ConfigListener {
public:
StatsLogProcessor(const sp<UidMap>& uidMap,
- const std::function<void(const vector<uint8_t>&)>& pushLog);
+ const std::function<void(const ConfigKey&)>& sendBroadcast);
virtual ~StatsLogProcessor();
virtual void OnLogEvent(const LogEvent& event);
@@ -41,15 +41,16 @@ public:
void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
- vector<uint8_t> onDumpReport(const ConfigKey& key);
+ size_t GetMetricsSize(const ConfigKey& key);
- /* Request a flush through a binder call. */
- void flush();
+ void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
private:
+ mutable mutex mBroadcastTimesMutex;
+
std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
- std::unordered_map<ConfigKey, long> mLastFlushTimes;
+ std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid.
@@ -60,17 +61,18 @@ private:
*/
static const size_t kMaxSerializedBytes = 16 * 1024;
- /* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush
- the logs to callback clients if true. */
+ /* Check if we should send a broadcast if approaching memory limits and if we're over, we
+ * actually delete the data. */
void flushIfNecessary(uint64_t timestampNs,
const ConfigKey& key,
const unique_ptr<MetricsManager>& metricsManager);
- std::function<void(const vector<uint8_t>&)> mPushLog;
+ // Function used to send a broadcast so that receiver for the config key can call getData
+ // to retrieve the stored data.
+ std::function<void(const ConfigKey& key)> mSendBroadcast;
- /* Minimum period between two flushes in nanoseconds. Currently set to 10
- * minutes. */
- static const unsigned long long kMinFlushPeriod = 600 * NS_PER_SEC;
+ /* Minimum period between two broadcasts in nanoseconds. Currently set to 60 seconds. */
+ static const unsigned long long kMinBroadcastPeriod = 60 * NS_PER_SEC;
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 11c5de172721..ef01ec7563f5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -17,17 +17,20 @@
#define DEBUG true
#include "Log.h"
+#include "android-base/stringprintf.h"
#include "StatsService.h"
+#include "config/ConfigKey.h"
+#include "config/ConfigManager.h"
#include "storage/DropboxReader.h"
#include <android-base/file.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
#include <utils/String16.h>
-
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -39,6 +42,9 @@ namespace android {
namespace os {
namespace statsd {
+constexpr const char* kPermissionDump = "android.permission.DUMP";
+#define STATS_SERVICE_DIR "/data/system/stats-service"
+
// ======================================================================
/**
* Watches for the death of the stats companion (system process).
@@ -67,8 +73,18 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
{
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
- mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) {
- pushLog(log);
+ mProcessor = new StatsLogProcessor(mUidMap, [this](const ConfigKey& key) {
+ auto sc = getStatsCompanionService();
+ auto receiver = mConfigManager->GetConfigReceiver(key);
+ if (sc == nullptr) {
+ ALOGD("Could not find StatsCompanionService");
+ } else if (receiver.first.size() == 0) {
+ ALOGD("Statscompanion could not find a broadcast receiver for %s",
+ key.ToString().c_str());
+ } else {
+ sc->sendBroadcast(String16(receiver.first.c_str()),
+ String16(receiver.second.c_str()));
+ }
});
mConfigManager->AddListener(mProcessor);
@@ -198,6 +214,18 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
return cmd_print_pulled_metrics(out, args);
}
+
+ if (!args[0].compare(String8("send-broadcast"))) {
+ return cmd_trigger_broadcast(out, args);
+ }
+
+ if (!args[0].compare(String8("print-stats"))) {
+ return cmd_print_stats(out);
+ }
+
+ if (!args[0].compare(String8("clear-config"))) {
+ return cmd_remove_config_files(out);
+ }
}
print_cmd_help(out);
@@ -215,7 +243,12 @@ void StatsService::print_cmd_help(FILE* out) {
fprintf(out, " Prints the UID, app name, version mapping.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmds stats pull-source [int] \n");
+ fprintf(out, "usage: adb shell cmd stats clear-config \n");
+ fprintf(out, "\n");
+ fprintf(out, " Removes all configs from disk.\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
fprintf(out, "\n");
fprintf(out, " Prints the output of a pulled metrics source (int indicates source)\n");
fprintf(out, "\n");
@@ -238,6 +271,65 @@ void StatsService::print_cmd_help(FILE* out) {
fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
fprintf(out, " calling uid is used.\n");
fprintf(out, " NAME The name of the configuration\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
+ fprintf(out, " Send a broadcast that triggers the subscriber to fetch metrics.\n");
+ fprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
+ fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ fprintf(out, " calling uid is used.\n");
+ fprintf(out, " NAME The name of the configuration\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats print-stats\n");
+ fprintf(out, " Prints some basic stats.\n");
+}
+
+status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
+ string name;
+ bool good = false;
+ int uid;
+ const int argCount = args.size();
+ if (argCount == 2) {
+ // Automatically pick the UID
+ uid = IPCThreadState::self()->getCallingUid();
+ // TODO: What if this isn't a binder call? Should we fail?
+ name.assign(args[1].c_str(), args[1].size());
+ good = true;
+ } else if (argCount == 3) {
+ // If it's a userdebug or eng build, then the shell user can
+ // impersonate other uids.
+ if (mEngBuild) {
+ const char* s = args[1].c_str();
+ if (*s != '\0') {
+ char* end = NULL;
+ uid = strtol(s, &end, 0);
+ if (*end == '\0') {
+ name.assign(args[2].c_str(), args[2].size());
+ good = true;
+ }
+ }
+ } else {
+ fprintf(out,
+ "The metrics can only be dumped for other UIDs on eng or userdebug "
+ "builds.\n");
+ }
+ }
+ if (!good) {
+ print_cmd_help(out);
+ return UNKNOWN_ERROR;
+ }
+ auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, name));
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ if (sc != nullptr) {
+ sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
+ ALOGD("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
+ args[2].c_str());
+ } else {
+ ALOGD("Could not access statsCompanion");
+ }
+
+ return NO_ERROR;
}
status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
@@ -341,7 +433,8 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
}
}
if (good) {
- mProcessor->onDumpReport(ConfigKey(uid, name));
+ vector<uint8_t> data;
+ mProcessor->onDumpReport(ConfigKey(uid, name), &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
fprintf(out, "See the StatsLogReport in logcat...\n");
@@ -357,6 +450,15 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
}
}
+status_t StatsService::cmd_print_stats(FILE* out) {
+ vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
+ for (const ConfigKey& key : configs) {
+ fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
+ mProcessor->GetMetricsSize(key));
+ }
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
long msec = 0;
@@ -384,6 +486,27 @@ status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>
return UNKNOWN_ERROR;
}
+status_t StatsService::cmd_remove_config_files(FILE* out) {
+ fprintf(out, "Trying to remove config files...\n");
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+ if (dir == NULL) {
+ fprintf(out, "No existing config files found exiting...\n");
+ return NO_ERROR;
+ }
+
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') continue;
+ string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
+ fprintf(out, "Deleting file %s\n", file_name.c_str());
+ if (remove(file_name.c_str())) {
+ fprintf(out, "Error deleting file %s\n", file_name.c_str());
+ }
+ }
+ return NO_ERROR;
+}
+
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
const vector<String16>& app) {
if (DEBUG) ALOGD("StatsService::informAllUidData was called");
@@ -520,32 +643,53 @@ void StatsService::OnLogEvent(const LogEvent& event) {
mProcessor->OnLogEvent(event);
}
-Status StatsService::requestPush() {
- mProcessor->flush();
- return Status::ok();
+Status StatsService::getData(const String16& key, vector <uint8_t>* output) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ ALOGD("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ if (checkCallingPermission(String16(kPermissionDump))) {
+ string keyStr = string(String8(key).string());
+ ConfigKey configKey(ipc->getCallingUid(), keyStr);
+ mProcessor->onDumpReport(configKey, output);
+ return Status::ok();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+ }
}
-Status StatsService::pushLog(const vector<uint8_t>& log) {
- std::lock_guard<std::mutex> lock(mLock);
- for (size_t i = 0; i < mCallbacks.size(); i++) {
- mCallbacks[i]->onReceiveLogs((vector<uint8_t>*)&log);
+Status StatsService::addConfiguration(const String16& key,
+ const vector <uint8_t>& config,
+ const String16& package, const String16& cls,
+ bool* success) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (checkCallingPermission(String16(kPermissionDump))) {
+ string keyString = string(String8(key).string());
+ ConfigKey configKey(ipc->getCallingUid(), keyString);
+ StatsdConfig cfg;
+ cfg.ParseFromArray(&config[0], config.size());
+ mConfigManager->UpdateConfig(configKey, cfg);
+ mConfigManager->SetConfigReceiver(configKey, string(String8(package).string()),
+ string(String8(cls).string()));
+ *success = true;
+ return Status::ok();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
- return Status::ok();
}
-Status StatsService::subscribeStatsLog(const sp<IStatsCallbacks>& callback) {
- std::lock_guard<std::mutex> lock(mLock);
- for (size_t i = 0; i < mCallbacks.size(); i++) {
- if (mCallbacks[i] == callback) {
- return Status::fromStatusT(-errno);
- }
+Status StatsService::removeConfiguration(const String16& key, bool* success) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (checkCallingPermission(String16(kPermissionDump))) {
+ string keyStr = string(String8(key).string());
+ mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), keyStr));
+ return Status::ok();
+ } else {
+ *success = false;
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
- mCallbacks.add(callback);
- IInterface::asBinder(callback)->linkToDeath(this);
- return Status::ok();
}
-void StatsService::binderDied(const wp<IBinder>& who) {
+void StatsService::binderDied(const wp <IBinder>& who) {
for (size_t i = 0; i < mCallbacks.size(); i++) {
if (IInterface::asBinder(mCallbacks[i]) == who) {
mCallbacks.removeAt(i);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fa92f65d264d..888f97b6e954 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -71,20 +71,22 @@ public:
virtual void OnLogEvent(const LogEvent& event);
/**
- * Binder call to force trigger pushLog. This would be called by callback
- * clients.
+ * Binder call for clients to request data for this configuration key.
*/
- virtual Status requestPush() override;
+ virtual Status getData(const String16& key, vector<uint8_t>* output) override;
/**
- * Pushes stats log entries from statsd to callback clients.
+ * Binder call to let clients send a configuration and indicate they're interested when they
+ * should requestData for this configuration.
*/
- Status pushLog(const vector<uint8_t>& log);
+ virtual Status addConfiguration(const String16& key, const vector <uint8_t>& config,
+ const String16& package, const String16& cls, bool* success)
+ override;
/**
- * Binder call to listen to statsd to send stats log entries.
+ * Binder call to allow clients to remove the specified configuration.
*/
- virtual Status subscribeStatsLog(const sp<IStatsCallbacks>& callbacks) override;
+ virtual Status removeConfiguration(const String16& key, bool* success) override;
// TODO: public for testing since statsd doesn't run when system starts. Change to private
// later.
@@ -120,11 +122,21 @@ private:
void print_cmd_help(FILE* out);
/**
+ * Trigger a broadcast.
+ */
+ status_t cmd_trigger_broadcast(FILE* out, Vector<String8>& args);
+
+ /**
* Handle the config sub-command.
*/
status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
/**
+ * Prints some basic stats to std out.
+ */
+ status_t cmd_print_stats(FILE* out);
+
+ /**
* Print the event log.
*/
status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
@@ -145,6 +157,11 @@ private:
status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
/**
+ * Removes all configs stored on disk.
+ */
+ status_t cmd_remove_config_files(FILE* out);
+
+ /**
* Update a configuration.
*/
void set_config(int uid, const string& name, const StatsdConfig& config);
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/atoms.proto
index 9ab07de96aa2..ba93febe8ad4 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -19,10 +19,10 @@ syntax = "proto2";
// TODO: Not the right package and class name
package android.os.statsd;
option java_package = "com.android.os";
-option java_outer_classname = "StatsEventProto";
+option java_outer_classname = "AtomsProto";
/**
- * The master event class. This message defines all of the available
+ * The master atom class. This message defines all of the available
* raw stats log events from the Android system, also known as "atoms."
*
* This field contains a single oneof with all of the available messages.
@@ -30,12 +30,12 @@ option java_outer_classname = "StatsEventProto";
* generates the android.util.StatsLog class, which contains the constants
* and methods that Android uses to log.
*
- * This StatsEvent class is not actually built into the Android system.
+ * This Atom class is not actually built into the Android system.
* Instead, statsd on Android constructs these messages synthetically,
* in the format defined here and in stats_log.proto.
*/
-message StatsEvent {
- // Pushed events start at 2.
+message Atom {
+ // Pushed atoms start at 2.
oneof pushed {
// For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
BleScanStateChanged ble_scan_state_changed = 2;
@@ -102,8 +102,7 @@ message WorkSource {
/*
* *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd
- * and Westworld.
+ * Below are all of the individual atoms that are logged by Android via statsd.
*
* RULES:
* - The field ids for each atom must start at 1, and count upwards by 1.
@@ -114,7 +113,7 @@ message WorkSource {
* - The types must be built-in protocol buffer types, namely, no sub-messages
* are allowed (yet). The bytes type is also not allowed.
* - The CamelCase name of the message type should match the
- * underscore_separated name as defined in StatsEvent.
+ * underscore_separated name as defined in Atom.
* - If an atom represents work that can be attributed to an app, there can
* be exactly one WorkSource field. It must be field number 1.
* - A field that is a uid should be a string field, tagged with the [xxx]
@@ -397,7 +396,7 @@ message WakelockStateChanged {
FULL = 1;
WINDOW = 2;
}
- optional int32 type = 2;
+ optional Type type = 2;
// The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
optional string tag = 3;
@@ -425,7 +424,7 @@ message UidWakelockStateChanged {
FULL = 1;
WINDOW = 2;
}
- optional int32 type = 2;
+ optional Type type = 2;
enum State {
OFF = 0;
@@ -852,7 +851,6 @@ message PowerStateSubsystemSleepStatePulled {
}
/**
-<<<<<<< HEAD
* Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
* behavior in its own uid. However, the metrics of these isolated uid's almost always should be
* attributed back to the parent (host) uid. One example is Chrome.
@@ -872,7 +870,6 @@ message IsolatedUidChanged {
}
/*
-<<<<<<< HEAD
* Pulls Cpu time per frequency.
* Note: this should be pulled for gauge metric only, without condition.
* The puller keeps internal state of last values. It should not be pulled by
diff --git a/cmds/statsd/src/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto
new file mode 100644
index 000000000000..58e225a317f0
--- /dev/null
+++ b/cmds/statsd/src/atoms_copy.proto
@@ -0,0 +1,910 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+
+// TODO: Not the right package and class name
+package android.os.statsd;
+option java_package = "com.android.os";
+option java_outer_classname = "AtomsProto";
+
+/**
+ * The master atom class. This message defines all of the available
+ * raw stats log events from the Android system, also known as "atoms."
+ *
+ * This field contains a single oneof with all of the available messages.
+ * The stats-log-api-gen tool runs as part of the Android build and
+ * generates the android.util.StatsLog class, which contains the constants
+ * and methods that Android uses to log.
+ *
+ * This Atom class is not actually built into the Android system.
+ * Instead, statsd on Android constructs these messages synthetically,
+ * in the format defined here and in stats_log.proto.
+ */
+message Atom {
+ // Pushed atoms start at 2.
+ oneof pushed {
+ // 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.
+ WakelockStateChanged wakelock_state_changed = 10;
+ 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;
+ BatteryLevelChanged battery_level_changed = 30;
+ ChargingStateChanged charging_state_changed = 31;
+ PluggedStateChanged plugged_state_changed = 32;
+ DeviceTemperatureReported device_temperature_reported = 33;
+ DeviceOnStatusChanged device_on_status_changed = 34;
+ WakeupAlarmOccurred wakeup_alarm_occurred = 35;
+ KernelWakeupReported kernel_wakeup_reported = 36;
+ WifiLockStateChanged wifi_lock_state_changed = 37;
+ WifiSignalStrengthChanged wifi_signal_strength_changed = 38;
+ WifiScanStateChanged wifi_scan_state_changed = 39;
+ PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
+ SettingChanged setting_changed = 41;
+ ActivityForegroundStateChanged activity_foreground_state_changed = 42;
+ IsolatedUidChanged isolated_uid_changed = 43;
+ // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
+ }
+
+ // Pulled events will start at field 1000.
+ oneof pulled {
+ WifiBytesTransferred wifi_bytes_transferred = 1000;
+ WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
+ MobileBytesTransferred mobile_bytes_transferred = 1002;
+ MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
+ KernelWakelockPulled kernel_wakelock_pulled = 1004;
+ PowerStatePlatformSleepStatePulled power_state_platform_sleep_state_pulled = 1005;
+ PowerStateVoterPulled power_state_voter_pulled = 1006;
+ PowerStateSubsystemSleepStatePulled power_state_subsystem_sleep_state_pulled = 1007;
+ CpuTimePerFreqPulled cpu_time_per_freq_pulled = 1008;
+ CpuTimePerUidPulled cpu_time_per_uid_pulled = 1009;
+ CpuTimePerUidFreqPulled cpu_time_per_uid_freq_pulled = 1010;
+ }
+}
+
+/**
+ * A WorkSource represents the chained attribution of applications that
+ * resulted in a particular bit of work being done.
+ */
+message WorkSource {
+ // TODO
+}
+
+/*
+ * *****************************************************************************
+ * Below are all of the individual atoms that are logged by Android via statsd.
+ *
+ * RULES:
+ * - The field ids for each atom must start at 1, and count upwards by 1.
+ * Skipping field ids is not allowed.
+ * - These form an API, so renaming, renumbering or removing fields is
+ * not allowed between android releases. (This is not currently enforced,
+ * but there will be a tool to enforce this restriction).
+ * - The types must be built-in protocol buffer types, namely, no sub-messages
+ * are allowed (yet). The bytes type is also not allowed.
+ * - The CamelCase name of the message type should match the
+ * underscore_separated name as defined in Atom.
+ * - If an atom represents work that can be attributed to an app, there can
+ * be exactly one WorkSource field. It must be field number 1.
+ * - A field that is a uid should be a string field, tagged with the [xxx]
+ * annotation. The generated code on android will be represented by UIDs,
+ * and those UIDs will be translated in xxx to those strings.
+ *
+ * CONVENTIONS:
+ * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
+ * - If there is a UID, it goes first. Think in an object-oriented fashion.
+ * *****************************************************************************
+ */
+
+/**
+ * Logs when the screen state changes.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenStateChanged {
+ // TODO: Use the real screen state.
+ enum State {
+ STATE_UNKNOWN = 0;
+ STATE_OFF = 1;
+ STATE_ON = 2;
+ STATE_DOZE = 3;
+ STATE_DOZE_SUSPEND = 4;
+ STATE_VR = 5;
+ }
+ // New screen state.
+ optional State display_state = 1;
+}
+
+/**
+ * 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 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 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 WakelockStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // Type of wakelock.
+ enum Type {
+ PARTIAL = 0;
+ FULL = 1;
+ WINDOW = 2;
+ }
+ optional Type 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 Type 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: 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;
+}
+
+/**
+ * Logs battery level (percent full, from 0 to 100).
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message BatteryLevelChanged {
+ // Battery level. Should be in [0, 100].
+ optional int32 battery_level = 1;
+}
+
+/**
+ * Logs change in charging status of the device.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message ChargingStateChanged {
+ // TODO: Link directly to BatteryManager.java's constants (via a proto).
+ enum State {
+ BATTERY_STATUS_UNKNOWN = 1;
+ BATTERY_STATUS_CHARGING = 2;
+ BATTERY_STATUS_DISCHARGING = 3;
+ BATTERY_STATUS_NOT_CHARGING = 4;
+ BATTERY_STATUS_FULL = 5;
+ }
+ optional State charging_state = 1;
+}
+
+/**
+ * Logs whether the device is plugged in, and what power source it is using.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PluggedStateChanged {
+ // TODO: Link directly to BatteryManager.java's constants (via a proto).
+ enum State {
+ // Note that NONE is not in BatteryManager.java's constants.
+ BATTERY_PLUGGED_NONE = 0;
+ // Power source is an AC charger.
+ BATTERY_PLUGGED_AC = 1;
+ // Power source is a USB port.
+ BATTERY_PLUGGED_USB = 2;
+ // Power source is wireless.
+ BATTERY_PLUGGED_WIRELESS = 4;
+ }
+ optional State plugged_state = 1;
+}
+
+/**
+ * Logs the temperature of the device, in tenths of a degree Celsius.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message DeviceTemperatureReported {
+ // Temperature in tenths of a degree C.
+ optional int32 temperature = 1;
+}
+
+// TODO: Define this more precisely.
+// TODO: Log the ON state somewhere. It isn't currently logged anywhere.
+/**
+ * Logs when the device turns off or on.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message DeviceOnStatusChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
+/**
+ * Logs when an app's wakeup alarm fires.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message WakeupAlarmOccurred {
+ // TODO: Add attribution instead of uid?
+ optional int32 uid = 1;
+}
+
+/**
+ * Logs kernel wakeup reasons and aborts.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message KernelWakeupReported {
+ // Name of the kernel wakeup reason (or abort).
+ optional string wakeup_reason_name = 1;
+
+ // Duration (in microseconds) for the wake-up interrupt to be serviced.
+ optional int64 duration_usec = 2;
+}
+
+/**
+ * Logs wifi locks held by an app.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message WifiLockStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs wifi signal strength changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message WifiSignalStrengthChanged {
+ // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
+ enum SignalStrength {
+ SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
+ SIGNAL_STRENGTH_POOR = 1;
+ SIGNAL_STRENGTH_MODERATE = 2;
+ SIGNAL_STRENGTH_GOOD = 3;
+ SIGNAL_STRENGTH_GREAT = 4;
+ }
+ optional SignalStrength signal_strength = 1;
+}
+
+/**
+ * Logs wifi scans performed by an app.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message WifiScanStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs phone signal strength changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PhoneSignalStrengthChanged {
+ // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
+ enum SignalStrength {
+ SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
+ SIGNAL_STRENGTH_POOR = 1;
+ SIGNAL_STRENGTH_MODERATE = 2;
+ SIGNAL_STRENGTH_GOOD = 3;
+ SIGNAL_STRENGTH_GREAT = 4;
+ }
+ optional SignalStrength signal_strength = 1;
+}
+
+/**
+ * Logs that a setting was updated.
+ * Logged from:
+ * frameworks/base/core/java/android/provider/Settings.java
+ * The tag and is_default allow resetting of settings to default values based on the specified
+ * tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details.
+ */
+message SettingChanged {
+ // The name of the setting.
+ optional string setting = 1;
+
+ // The change being imposed on this setting. May represent a number, eg "3".
+ optional string value = 2;
+
+ // The new value of this setting. For most settings, this is same as value. For some settings,
+ // value is +X or -X where X represents an element in a set. For example, if the previous value
+ // is A,B,C and value is -B, then new_value is A,C and prev_value is A,B,C.
+ // The +/- feature is currently only used for location_providers_allowed.
+ optional string new_value = 3;
+
+ // The previous value of this setting.
+ optional string prev_value = 4;
+
+ // The tag used with the is_default for resetting sets of settings. This is generally null.
+ optional string tag = 5;
+
+ // 1 indicates that this setting with tag should be resettable.
+ optional int32 is_default = 6;
+
+ // The user ID associated. Defined in android/os/UserHandle.java
+ optional int32 user = 7;
+}
+
+/*
+ * Logs activity going to foreground or background
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
+ */
+message ActivityForegroundStateChanged {
+ enum Activity {
+ MOVE_TO_BACKGROUND = 0;
+ MOVE_TO_FOREGROUND = 1;
+ }
+ optional int32 uid = 1;
+ optional string pkg_name = 2;
+ optional string class_name = 3;
+ optional Activity activity = 4;
+}
+
+/**
+ * Pulls bytes transferred via wifi (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferred {
+ optional int32 uid = 1;
+
+ optional int64 rx_bytes = 2;
+
+ optional int64 rx_packets = 3;
+
+ optional int64 tx_bytes = 4;
+
+ optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via wifi (separated by foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferredByFgBg {
+ optional int32 uid = 1;
+
+ // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ optional int32 is_foreground = 2;
+
+ optional int64 rx_bytes = 3;
+
+ optional int64 rx_packets = 4;
+
+ optional int64 tx_bytes = 5;
+
+ optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferred {
+ optional int32 uid = 1;
+
+ optional int64 rx_bytes = 2;
+
+ optional int64 rx_packets = 3;
+
+ optional int64 tx_bytes = 4;
+
+ optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (separated by foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferredByFgBg {
+ optional int32 uid = 1;
+
+ // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ optional int32 is_foreground = 2;
+
+ optional int64 rx_bytes = 3;
+
+ optional int64 rx_packets = 4;
+
+ optional int64 tx_bytes = 5;
+
+ optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls the kernel wakelock durations. This atom is adapted from
+ * android/internal/os/KernelWakelockStats.java
+ *
+ * Pulled from:
+ * StatsCompanionService using KernelWakelockReader.
+ */
+message KernelWakelockPulled {
+ optional string name = 1;
+
+ optional int32 count = 2;
+
+ optional int32 version = 3;
+
+ optional int64 time = 4;
+}
+
+/*
+ * Pulls PowerStatePlatformSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStatePlatformSleepStatePulled {
+ optional string name = 1;
+ optional uint64 residency_in_msec_since_boot = 2;
+ optional uint64 total_transitions = 3;
+ optional bool supported_only_in_suspend = 4;
+}
+
+/**
+ * Pulls PowerStateVoter.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStateVoterPulled {
+ optional string power_state_platform_sleep_state_name = 1;
+ optional string power_state_voter_name = 2;
+ optional uint64 total_time_in_msec_voted_for_since_boot = 3;
+ optional uint64 total_number_of_times_voted_since_boot = 4;
+}
+
+/**
+ * Pulls PowerStateSubsystemSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.1/types.hal
+ */
+message PowerStateSubsystemSleepStatePulled {
+ optional string power_state_subsystem_name = 1;
+ optional string power_state_subsystem_sleep_state_name = 2;
+ optional uint64 residency_in_msec_since_boot = 3;
+ optional uint64 total_transitions = 4;
+ optional uint64 last_entry_timestamp_ms = 5;
+ optional bool supported_only_in_suspend = 6;
+}
+
+/**
+ * Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
+ * behavior in its own uid. However, the metrics of these isolated uid's almost always should be
+ * attributed back to the parent (host) uid. One example is Chrome.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message IsolatedUidChanged {
+ // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
+ optional int32 parent_uid = 1;
+
+ optional int32 isolated_uid = 2;
+
+ // 1 denotes we're creating an isolated uid and 0 denotes removal. We expect an isolated uid to
+ // be removed before if it's used for another parent uid.
+ optional int32 is_create = 3;
+}
+
+/*
+ * Pulls Cpu time per frequency.
+ * Note: this should be pulled for gauge metric only, without condition.
+ * The puller keeps internal state of last values. It should not be pulled by
+ * different metrics.
+ * The pulled data is delta of cpu time from last pull, calculated as
+ * following:
+ * if current time is larger than last value, take delta between the two.
+ * if current time is smaller than last value, there must be a cpu
+ * hotplug event, and the current time is taken as delta.
+ */
+message CpuTimePerFreqPulled {
+ optional uint32 cluster = 1;
+ optional uint32 freq_index = 2;
+ optional uint64 time = 3;
+}
+
+/*
+ * Pulls Cpu Time Per Uid.
+ * Note that isolated process uid time should be attributed to host uids.
+ */
+message CpuTimePerUidPulled {
+ optional uint64 uid = 1;
+ optional uint64 user_time_ms = 2;
+ optional uint64 sys_time_ms = 3;
+}
+
+/**
+ * Pulls Cpu Time Per Uid per frequency.
+ * Note that isolated process uid time should be attributed to host uids.
+ * For each uid, we order the time by descending frequencies.
+ */
+message CpuTimePerUidFreqPulled {
+ optional uint64 uid = 1;
+ optional uint64 freq_idx = 2;
+ optional uint64 time_ms = 3;
+}
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index a694dbf754ef..60060fe60fbd 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -206,7 +206,7 @@ void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
vector<bool>& conditionChangedCache) {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
- VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState);
+ VLOG("Yes, already evaluated, %s %d", mName.c_str(), conditionCache[mIndex]);
return;
}
@@ -230,8 +230,23 @@ void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
}
if (matchedState < 0) {
+ // The event doesn't match this condition. So we just report existing condition values.
conditionChangedCache[mIndex] = false;
- conditionCache[mIndex] = mNonSlicedConditionState;
+ if (mSliced) {
+ // if the condition result is sliced. metrics won't directly get value from the
+ // cache, so just set any value other than kNotEvaluated.
+ conditionCache[mIndex] = ConditionState::kUnknown;
+ } else if (mSlicedConditionState.find(DEFAULT_DIMENSION_KEY) ==
+ mSlicedConditionState.end()) {
+ // condition not sliced, but we haven't seen the matched start or stop yet. so return
+ // initial value.
+ conditionCache[mIndex] = mInitialValue;
+ } else {
+ // return the cached condition.
+ conditionCache[mIndex] = mSlicedConditionState[DEFAULT_DIMENSION_KEY] > 0
+ ? ConditionState::kTrue
+ : ConditionState::kFalse;
+ }
return;
}
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 2618a217c378..669a4b77f3b4 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -86,6 +86,9 @@ ConditionState evaluateCombinationCondition(const std::vector<int>& children,
case LogicalOperation::NOR:
newCondition = hasTrue ? ConditionState::kFalse : ConditionState::kTrue;
break;
+ case LogicalOperation::LOGICAL_OPERATION_UNSPECIFIED:
+ newCondition = ConditionState::kFalse;
+ break;
}
return newCondition;
}
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index bbf20fd1acf7..3489c43c8052 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -78,7 +78,7 @@ inline ostream& operator<<(ostream& os, const ConfigKey& config) {
/**
* A hash function for ConfigKey so it can be used for unordered_map/set.
- * Unfortunately this hast to go in std namespace because C++ is fun!
+ * Unfortunately this has to go in std namespace because C++ is fun!
*/
namespace std {
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 1e1d88ec142a..21256097a766 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -18,16 +18,23 @@
#include "stats_util.h"
-#include <vector>
-
+#include <android-base/file.h>
+#include <dirent.h>
#include <stdio.h>
+#include <vector>
+#include "android-base/stringprintf.h"
namespace android {
namespace os {
namespace statsd {
+#define STATS_SERVICE_DIR "/data/system/stats-service"
+
static StatsdConfig build_fake_config();
+using android::base::StringPrintf;
+using std::unique_ptr;
+
ConfigManager::ConfigManager() {
}
@@ -35,11 +42,10 @@ ConfigManager::~ConfigManager() {
}
void ConfigManager::Startup() {
- // TODO: Implement me -- read from storage and call onto all of the listeners.
- // Instead, we'll just make a fake one.
+ readConfigFromDisk();
// this should be called from StatsService when it receives a statsd_config
- UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
+ UpdateConfig(ConfigKey(1000, "fake"), build_fake_config());
}
void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
@@ -52,7 +58,7 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
// Why doesn't this work? mConfigs.insert({key, config});
// Save to disk
- update_saved_configs();
+ update_saved_configs(key, config);
// Tell everyone
for (auto& listener : mListeners) {
@@ -60,21 +66,47 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
}
}
+void ConfigManager::SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls) {
+ mConfigReceivers[key] = pair<string, string>(pkg, cls);
+}
+
+void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
+ mConfigReceivers.erase(key);
+}
+
void ConfigManager::RemoveConfig(const ConfigKey& key) {
unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
if (it != mConfigs.end()) {
// Remove from map
mConfigs.erase(it);
- // Save to disk
- update_saved_configs();
-
// Tell everyone
for (auto& listener : mListeners) {
listener->OnConfigRemoved(key);
}
}
- // If we didn't find it, just quietly ignore it.
+
+ // Remove from disk. There can still be a lingering file on disk so we check
+ // whether or not the config was on memory.
+ remove_saved_configs(key);
+}
+
+void ConfigManager::remove_saved_configs(const ConfigKey& key) {
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+ if (dir == NULL) {
+ ALOGD("no default config on disk");
+ return;
+ }
+ string prefix = StringPrintf("%d-%s", key.GetUid(), key.GetName().c_str());
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] != '.' && strncmp(name, prefix.c_str(), prefix.size()) == 0) {
+ if (remove(StringPrintf("%s/%s", STATS_SERVICE_DIR, name).c_str()) != 0) {
+ ALOGD("no file found");
+ }
+ }
+ }
}
void ConfigManager::RemoveConfigs(int uid) {
@@ -85,6 +117,7 @@ void ConfigManager::RemoveConfigs(int uid) {
if (it->first.GetUid() == uid) {
removed.push_back(it->first);
it = mConfigs.erase(it);
+ mConfigReceivers.erase(it->first);
} else {
it++;
}
@@ -99,18 +132,101 @@ void ConfigManager::RemoveConfigs(int uid) {
}
}
+vector<ConfigKey> ConfigManager::GetAllConfigKeys() {
+ vector<ConfigKey> ret;
+ for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
+ ret.push_back(it->first);
+ }
+ return ret;
+}
+
+const pair<string, string> ConfigManager::GetConfigReceiver(const ConfigKey& key) {
+ auto it = mConfigReceivers.find(key);
+ if (it == mConfigReceivers.end()) {
+ return pair<string,string>();
+ } else {
+ return it->second;
+ }
+}
+
void ConfigManager::Dump(FILE* out) {
fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
fprintf(out, " uid name\n");
for (unordered_map<ConfigKey, StatsdConfig>::const_iterator it = mConfigs.begin();
it != mConfigs.end(); it++) {
fprintf(out, " %6d %s\n", it->first.GetUid(), it->first.GetName().c_str());
+ auto receiverIt = mConfigReceivers.find(it->first);
+ if (receiverIt != mConfigReceivers.end()) {
+ fprintf(out, " -> received by %s, %s\n", receiverIt->second.first.c_str(),
+ receiverIt->second.second.c_str());
+ }
// TODO: Print the contents of the config too.
}
}
-void ConfigManager::update_saved_configs() {
- // TODO: Implement me -- write to disk.
+void ConfigManager::readConfigFromDisk() {
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+ if (dir == NULL) {
+ ALOGD("no default config on disk");
+ return;
+ }
+
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') continue;
+ ALOGD("file %s", name);
+
+ int index = 0;
+ int uid = 0;
+ string configName;
+ char* substr = strtok(name, "-");
+ // Timestamp lives at index 2 but we skip parsing it as it's not needed.
+ while (substr != nullptr && index < 2) {
+ if (index) {
+ uid = atoi(substr);
+ } else {
+ configName = substr;
+ }
+ index++;
+ }
+ if (index < 2) continue;
+ string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
+ ALOGD("full file %s", file_name.c_str());
+ int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ string content;
+ if (android::base::ReadFdToString(fd, &content)) {
+ StatsdConfig config;
+ if (config.ParseFromString(content)) {
+ mConfigs[ConfigKey(uid, configName)] = config;
+ ALOGD("map key uid=%d|name=%s", uid, name);
+ }
+ }
+ close(fd);
+ }
+ }
+}
+
+void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
+ mkdir(STATS_SERVICE_DIR, S_IRWXU);
+
+ // If there is a pre-existing config with same key we should first delete it.
+ remove_saved_configs(key);
+
+ // Then we save the latest config.
+ string file_name = StringPrintf("%s/%d-%s-%ld", STATS_SERVICE_DIR, key.GetUid(),
+ key.GetName().c_str(), time(nullptr));
+ int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+ if (fd != -1) {
+ const int numBytes = config.ByteSize();
+ vector<uint8_t> buffer(numBytes);
+ config.SerializeToArray(&buffer[0], numBytes);
+ int result = write(fd, &buffer[0], numBytes);
+ close(fd);
+ bool wroteKey = (result == numBytes);
+ ALOGD("wrote to file %d", wroteKey);
+ }
}
static StatsdConfig build_fake_config() {
@@ -152,7 +268,7 @@ static StatsdConfig build_fake_config() {
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
// Anomaly threshold for screen-on count.
- Alert* alert = config.add_alerts();
+ Alert* alert = config.add_alert();
alert->set_name("1");
alert->set_number_of_buckets(6);
alert->set_trigger_if_sum_gt(10);
@@ -167,7 +283,7 @@ static StatsdConfig build_fake_config() {
keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
// Anomaly threshold for background count.
- alert = config.add_alerts();
+ alert = config.add_alert();
alert->set_name("2");
alert->set_number_of_buckets(4);
alert->set_trigger_if_sum_gt(30);
@@ -199,11 +315,11 @@ static StatsdConfig build_fake_config() {
DurationMetric* durationMetric = config.add_duration_metric();
durationMetric->set_name("5");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
- durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
keyMatcher = durationMetric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
@@ -213,11 +329,11 @@ static StatsdConfig build_fake_config() {
durationMetric = config.add_duration_metric();
durationMetric->set_name("6");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
- durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
keyMatcher = durationMetric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
@@ -227,9 +343,9 @@ static StatsdConfig build_fake_config() {
durationMetric = config.add_duration_metric();
durationMetric->set_name("7");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
- durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
@@ -239,7 +355,7 @@ static StatsdConfig build_fake_config() {
durationMetric = config.add_duration_metric();
durationMetric->set_name("8");
durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L);
- durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
durationMetric->set_what("SCREEN_IS_ON");
// Value metric to count KERNEL_WAKELOCK when screen turned on
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 5d73eaf3c7b6..01d7fb969230 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -32,6 +32,7 @@ using android::RefBase;
using std::string;
using std::unordered_map;
using std::vector;
+using std::pair;
/**
* Keeps track of which configurations have been set from various sources.
@@ -45,9 +46,7 @@ public:
virtual ~ConfigManager();
/**
- * Call to load the saved configs from disk.
- *
- * TODO: Implement me
+ * Initialize ConfigListener by reading from disk and get updates.
*/
void Startup();
@@ -64,6 +63,26 @@ public:
void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
/**
+ * Sets the broadcast receiver for a configuration key.
+ */
+ void SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls);
+
+ /**
+ * Returns the package name and class name representing the broadcast receiver for this config.
+ */
+ const pair<string, string> GetConfigReceiver(const ConfigKey& key);
+
+ /**
+ * Returns all config keys registered.
+ */
+ vector<ConfigKey> GetAllConfigKeys();
+
+ /**
+ * Erase any broadcast receiver associated with this config key.
+ */
+ void RemoveConfigReceiver(const ConfigKey& key);
+
+ /**
* A configuration was removed.
*
* Reports this to listeners.
@@ -84,17 +103,33 @@ private:
/**
* Save the configs to disk.
*/
- void update_saved_configs();
+ void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);
+
+ /**
+ * Remove saved configs from disk.
+ */
+ void remove_saved_configs(const ConfigKey& key);
/**
- * The Configs that have been set
+ * The Configs that have been set. Each config should
*/
unordered_map<ConfigKey, StatsdConfig> mConfigs;
/**
+ * Each config key can be subscribed by up to one receiver, specified as the package name and
+ * class name.
+ */
+ unordered_map<ConfigKey, pair<string, string>> mConfigReceivers;
+
+ /**
* The ConfigListeners that will be told about changes.
*/
vector<sp<ConfigListener>> mListeners;
+
+ /**
+ * Call to load the saved configs from disk.
+ */
+ void readConfigFromDisk();
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index e004d217a966..e2745d21af3d 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -71,10 +71,9 @@ bool CpuTimePerUidFreqPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>
do {
timeMs = std::stoull(pch);
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ_PULLED, timestamp);
- auto elemList = ptr->GetAndroidLogEventList();
- *elemList << uid;
- *elemList << idx;
- *elemList << timeMs;
+ ptr->write(uid);
+ ptr->write(idx);
+ ptr->write(timeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index b84b877a0ee9..e0572dca679d 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -66,10 +66,9 @@ bool CpuTimePerUidPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* da
uint64_t sysTimeMs = std::stoull(pch);
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_PULLED, timestamp);
- auto elemList = ptr->GetAndroidLogEventList();
- *elemList << uid;
- *elemList << userTimeMs;
- *elemList << sysTimeMs;
+ ptr->write(uid);
+ ptr->write(userTimeMs);
+ ptr->write(sysTimeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs, (long long)sysTimeMs);
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
index 319feef49b35..3ee636dfcde5 100644
--- a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
@@ -93,11 +93,10 @@ bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEven
auto statePtr = make_shared<LogEvent>(
android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED, timestamp);
- auto elemList = statePtr->GetAndroidLogEventList();
- *elemList << state.name;
- *elemList << state.residencyInMsecSinceBoot;
- *elemList << state.totalTransitions;
- *elemList << state.supportedOnlyInSuspend;
+ statePtr->write(state.name);
+ statePtr->write(state.residencyInMsecSinceBoot);
+ statePtr->write(state.totalTransitions);
+ statePtr->write(state.supportedOnlyInSuspend);
statePtr->init();
data->push_back(statePtr);
VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
@@ -106,11 +105,10 @@ bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEven
for (auto voter : state.voters) {
auto voterPtr =
make_shared<LogEvent>(android::util::POWER_STATE_VOTER_PULLED, timestamp);
- auto elemList = voterPtr->GetAndroidLogEventList();
- *elemList << state.name;
- *elemList << voter.name;
- *elemList << voter.totalTimeInMsecVotedForSinceBoot;
- *elemList << voter.totalNumberOfTimesVotedSinceBoot;
+ voterPtr->write(state.name);
+ voterPtr->write(voter.name);
+ voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
+ voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
voterPtr->init();
data->push_back(voterPtr);
VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
@@ -141,13 +139,12 @@ bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEven
const PowerStateSubsystemSleepState& state = subsystem.states[j];
auto subsystemStatePtr = make_shared<LogEvent>(
android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED, timestamp);
- auto elemList = subsystemStatePtr->GetAndroidLogEventList();
- *elemList << subsystem.name;
- *elemList << state.name;
- *elemList << state.residencyInMsecSinceBoot;
- *elemList << state.totalTransitions;
- *elemList << state.lastEntryTimestampMs;
- *elemList << state.supportedOnlyInSuspend;
+ subsystemStatePtr->write(subsystem.name);
+ subsystemStatePtr->write(state.name);
+ subsystemStatePtr->write(state.residencyInMsecSinceBoot);
+ subsystemStatePtr->write(state.totalTransitions);
+ subsystemStatePtr->write(state.lastEntryTimestampMs);
+ subsystemStatePtr->write(state.supportedOnlyInSuspend);
subsystemStatePtr->init();
data->push_back(subsystemStatePtr);
VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 913b906986c3..103213830914 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -29,21 +29,71 @@ using std::ostringstream;
using std::string;
using android::util::ProtoOutputStream;
-// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
-// for strings is not cleared before we can read them.
-LogEvent::LogEvent(log_msg& msg) : mList(msg) {
- init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
+LogEvent::LogEvent(log_msg& msg) {
+ mContext =
+ create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
+ mTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ init(mContext);
}
-LogEvent::LogEvent(int tag, uint64_t timestampNs) : mList(tag), mTimestampNs(timestampNs) {
+LogEvent::LogEvent(int32_t tagId, uint64_t timestampNs) {
+ mTimestampNs = timestampNs;
+ mTagId = tagId;
+ mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
+ if (mContext) {
+ android_log_write_int32(mContext, tagId);
+ }
}
-LogEvent::~LogEvent() {
+void LogEvent::init() {
+ if (mContext) {
+ const char* buffer;
+ size_t len = android_log_write_list_buffer(mContext, &buffer);
+ // turns to reader mode
+ mContext = create_android_log_parser(buffer, len);
+ init(mContext);
+ }
}
-void LogEvent::init() {
- mList.convert_to_reader();
- init(mTimestampNs, &mList);
+bool LogEvent::write(int32_t value) {
+ if (mContext) {
+ return android_log_write_int32(mContext, value) >= 0;
+ }
+ return false;
+}
+
+bool LogEvent::write(uint32_t value) {
+ if (mContext) {
+ return android_log_write_int32(mContext, value) >= 0;
+ }
+ return false;
+}
+
+bool LogEvent::write(uint64_t value) {
+ if (mContext) {
+ return android_log_write_int64(mContext, value) >= 0;
+ }
+ return false;
+}
+
+bool LogEvent::write(const string& value) {
+ if (mContext) {
+ return android_log_write_string8_len(mContext, value.c_str(), value.length()) >= 0;
+ }
+ return false;
+}
+
+bool LogEvent::write(float value) {
+ if (mContext) {
+ return android_log_write_float32(mContext, value) >= 0;
+ }
+ return false;
+}
+
+LogEvent::~LogEvent() {
+ if (mContext) {
+ android_log_destroy(&mContext);
+ }
}
/**
@@ -51,22 +101,25 @@ void LogEvent::init() {
* The goal is to do as little preprocessing as possible, because we read a tiny fraction
* of the elements that are written to the log.
*/
-void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
- mTimestampNs = timestampNs;
- mTagId = reader->tag();
-
+void LogEvent::init(android_log_context context) {
mElements.clear();
android_log_list_element elem;
-
// TODO: The log is actually structured inside one list. This is convenient
// because we'll be able to use it to put the attribution (WorkSource) block first
// without doing our own tagging scheme. Until that change is in, just drop the
// list-related log elements and the order we get there is our index-keyed data
// structure.
+ int i = 0;
do {
- elem = android_log_read_next(reader->context());
+ elem = android_log_read_next(context);
switch ((int)elem.type) {
case EVENT_TYPE_INT:
+ // elem at [0] is EVENT_TYPE_LIST, [1] is the tag id. If we add WorkSource, it would
+ // be the list starting at [2].
+ if (i == 1) {
+ mTagId = elem.data.int32;
+ break;
+ }
case EVENT_TYPE_FLOAT:
case EVENT_TYPE_STRING:
case EVENT_TYPE_LONG:
@@ -81,13 +134,10 @@ void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
default:
break;
}
+ i++;
} while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
}
-android_log_event_list* LogEvent::GetAndroidLogEventList() {
- return &mList;
-}
-
int64_t LogEvent::GetLong(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 298494049628..7e8a96b2114e 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -21,6 +21,7 @@
#include <android/util/ProtoOutputStream.h>
#include <log/log_event_list.h>
#include <log/log_read.h>
+#include <private/android_logger.h>
#include <utils/Errors.h>
#include <memory>
@@ -45,12 +46,9 @@ public:
explicit LogEvent(log_msg& msg);
/**
- * Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
- * mode. Obtain this list with the getter. Make sure to call init() before attempting to read
- * any of the values. This constructor is useful for unit-testing since we can't pass in an
- * android_log_event_list since there is no copy constructor or assignment operator available.
+ * Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
*/
- explicit LogEvent(int tag, uint64_t timestampNs);
+ explicit LogEvent(int32_t tagId, uint64_t timestampNs);
~LogEvent();
@@ -76,6 +74,17 @@ public:
float GetFloat(size_t key, status_t* err) const;
/**
+ * Write test data to the LogEvent. This can only be used when the LogEvent is constructed
+ * using LogEvent(tagId, timestampNs). You need to call init() before you can read from it.
+ */
+ bool write(uint32_t value);
+ bool write(int32_t value);
+ bool write(uint64_t value);
+ bool write(int64_t value);
+ bool write(const string& value);
+ bool write(float value);
+
+ /**
* Return a string representation of this event.
*/
string ToString() const;
@@ -91,13 +100,6 @@ public:
KeyValuePair GetKeyValueProto(size_t key) const;
/**
- * A pointer to the contained log_event_list.
- *
- * @return The android_log_event_list contained within.
- */
- android_log_event_list* GetAndroidLogEventList();
-
- /**
* Used with the constructor where tag is passed in. Converts the log_event_list to read mode
* and prepares the list for reading.
*/
@@ -113,16 +115,11 @@ private:
/**
* Parses a log_msg into a LogEvent object.
*/
- void init(const log_msg& msg);
-
- /**
- * Parses a log_msg into a LogEvent object.
- */
- void init(int64_t timestampNs, android_log_event_list* reader);
+ void init(android_log_context context);
vector<android_log_list_element> mElements;
- // Need a copy of the android_log_event_list so the strings are not cleared.
- android_log_event_list mList;
+
+ android_log_context mContext;
uint64_t mTimestampNs;
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a7402800630e..41b24bc5ebd6 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index cccc9b3317e7..f7352cd1190c 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -84,6 +84,9 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera
}
}
break;
+ case LogicalOperation::LOGICAL_OPERATION_UNSPECIFIED:
+ matched = false;
+ break;
}
return matched;
}
@@ -112,6 +115,7 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (err == NO_ERROR && val != NULL) {
if (!(cur.eq_string() == val)) {
allMatched = false;
+ break;
}
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt ||
@@ -126,26 +130,30 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt) {
if (!(val == cur.eq_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt) {
if (!(val < cur.lt_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtInt) {
if (!(val > cur.gt_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLteInt) {
if (!(val <= cur.lte_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGteInt) {
if (!(val >= cur.gte_int())) {
allMatched = false;
+ break;
}
}
}
- break;
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) {
// Boolean fields
status_t err = NO_ERROR;
@@ -153,21 +161,24 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (err == NO_ERROR) {
if (!(cur.eq_bool() == val)) {
allMatched = false;
+ break;
}
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat ||
matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
// Float fields
status_t err = NO_ERROR;
- bool val = event.GetFloat(key, &err);
+ float val = event.GetFloat(key, &err);
if (err == NO_ERROR) {
if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat) {
- if (!(cur.lt_float() <= val)) {
+ if (!(val < cur.lt_float())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
- if (!(cur.gt_float() >= val)) {
+ if (!(val > cur.gt_float())) {
allMatched = false;
+ break;
}
}
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index aaf3ec2c298b..eba2e06035e5 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -63,6 +63,7 @@ const int FIELD_ID_DURATION = 3;
DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex,
+ const bool nesting,
const sp<ConditionWizard>& wizard,
const vector<KeyMatcher>& internalDimension,
const uint64_t startTimeNs)
@@ -71,6 +72,7 @@ DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
mStartIndex(startIndex),
mStopIndex(stopIndex),
mStopAllIndex(stopAllIndex),
+ mNested(nesting),
mInternalDimension(internalDimension) {
// TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
// them in the base class, because the proto generated CountMetric, and DurationMetric are
@@ -109,13 +111,13 @@ void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
vector<DurationBucket>& bucket) {
- switch (mMetric.type()) {
- case DurationMetric_AggregationType_DURATION_SUM:
- return make_unique<OringDurationTracker>(mWizard, mConditionTrackerIndex,
+ switch (mMetric.aggregation_type()) {
+ case DurationMetric_AggregationType_SUM:
+ return make_unique<OringDurationTracker>(mWizard, mConditionTrackerIndex, mNested,
mCurrentBucketStartTimeNs, mBucketSizeNs,
bucket);
- case DurationMetric_AggregationType_DURATION_MAX_SPARSE:
- return make_unique<MaxDurationTracker>(mWizard, mConditionTrackerIndex,
+ case DurationMetric_AggregationType_MAX_SPARSE:
+ return make_unique<MaxDurationTracker>(mWizard, mConditionTrackerIndex, mNested,
mCurrentBucketStartTimeNs, mBucketSizeNs,
bucket);
}
@@ -220,10 +222,8 @@ std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
(long long)mCurrentBucketStartTimeNs);
std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
startNewProtoOutputStream(endTime);
- mPastBuckets.clear();
-
+ // TODO: Properly clear the old buckets.
return buffer;
}
@@ -233,10 +233,12 @@ void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
}
VLOG("flushing...........");
- for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end(); ++it) {
+ for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end();) {
if (it->second->flushIfNeeded(eventTime)) {
VLOG("erase bucket for key %s", it->first.c_str());
- mCurrentSlicedDuration.erase(it);
+ it = mCurrentSlicedDuration.erase(it);
+ } else {
+ ++it;
}
}
@@ -268,7 +270,7 @@ void DurationMetricProducer::onMatchedLogEventInternal(
if (matcherIndex == mStartIndex) {
it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
} else if (matcherIndex == mStopIndex) {
- it->second->noteStop(atomKey, event.GetTimestampNs());
+ it->second->noteStop(atomKey, event.GetTimestampNs(), false);
}
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index eea00454d5e6..bb5d4d94dea8 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -39,7 +39,8 @@ class DurationMetricProducer : public MetricProducer {
public:
DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex,
const size_t startIndex, const size_t stopIndex,
- const size_t stopAllIndex, const sp<ConditionWizard>& wizard,
+ const size_t stopAllIndex, const bool nesting,
+ const sp<ConditionWizard>& wizard,
const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs);
virtual ~DurationMetricProducer();
@@ -80,6 +81,9 @@ private:
// Index of the SimpleLogEntryMatcher which defines the stop all for all dimensions.
const size_t mStopAllIndex;
+ // nest counting -- for the same key, stops must match the number of starts to make real stop
+ const bool mNested;
+
// The dimension from the atom predicate. e.g., uid, wakelock name.
const vector<KeyMatcher> mInternalDimension;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index b2ffb2fc6ff5..9a94a0efa850 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -49,7 +49,7 @@ const int FIELD_ID_EVENT_METRICS = 4;
const int FIELD_ID_DATA = 1;
// for EventMetricData
const int FIELD_ID_TIMESTAMP_NANOS = 1;
-const int FIELD_ID_STATS_EVENTS = 2;
+const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& wizard,
@@ -96,7 +96,6 @@ std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
startNewProtoOutputStream(endTime);
- mByteSize = 0;
return buffer;
}
@@ -117,15 +116,14 @@ void EventMetricProducer::onMatchedLogEventInternal(
long long wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
- long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
+ long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
event.ToProto(*mProto);
mProto->end(eventToken);
mProto->end(wrapperToken);
- // TODO: Find a proper way to derive the size of incoming LogEvent.
}
size_t EventMetricProducer::byteSize() {
- return mByteSize;
+ return mProto->bytesWritten();
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 77406216f421..0dccdf493869 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -65,8 +65,6 @@ protected:
private:
const EventMetric mMetric;
-
- size_t mByteSize;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index c0930e381ce3..c7982a837c14 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -61,12 +61,15 @@ public:
// TODO: Pass a timestamp as a parameter in onDumpReport and update all its
// implementations.
+ // onDumpReport returns the proto-serialized output and clears the previously stored contents.
virtual std::unique_ptr<std::vector<uint8_t>> onDumpReport() = 0;
virtual bool isConditionSliced() const {
return mConditionSliced;
};
+ // Returns the memory in bytes currently used to store this metric's data. Does not change
+ // state.
virtual size_t byteSize() = 0;
protected:
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 39c79f99daca..fb167798a44f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,6 +46,8 @@ public:
// Config source owner can call onDumpReport() to get all the metrics collected.
std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
+ // Computes the total byte size of all metrics managed by a single config source.
+ // Does not change the state.
size_t byteSize();
private:
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 5c76d0e6513b..18b334988d0d 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -34,6 +34,10 @@ enum DurationState {
// Hold duration information for one atom level duration in current on-going bucket.
struct DurationInfo {
DurationState state;
+
+ // the number of starts seen.
+ int32_t startCount;
+
// most recent start time.
int64_t lastStartTime;
// existing duration in current bucket.
@@ -42,7 +46,7 @@ struct DurationInfo {
// cache the HashableDimensionKeys we need to query the condition for this duration event.
ConditionKey conditionKeys;
- DurationInfo() : state(kStopped), lastStartTime(0), lastDuration(0){};
+ DurationInfo() : state(kStopped), startCount(0), lastStartTime(0), lastDuration(0){};
};
struct DurationBucket {
@@ -53,18 +57,21 @@ struct DurationBucket {
class DurationTracker {
public:
- DurationTracker(sp<ConditionWizard> wizard, int conditionIndex, uint64_t currentBucketStartNs,
- uint64_t bucketSizeNs, std::vector<DurationBucket>& bucket)
+ DurationTracker(sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
+ uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ std::vector<DurationBucket>& bucket)
: mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
- mCurrentBucketStartTimeNs(currentBucketStartNs),
mBucketSizeNs(bucketSizeNs),
+ mNested(nesting),
+ mCurrentBucketStartTimeNs(currentBucketStartNs),
mBucket(bucket),
mDuration(0){};
virtual ~DurationTracker(){};
virtual void noteStart(const HashableDimensionKey& key, bool condition,
const uint64_t eventTime, const ConditionKey& conditionKey) = 0;
- virtual void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) = 0;
+ virtual void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
+ const bool stopAll) = 0;
virtual void noteStopAll(const uint64_t eventTime) = 0;
virtual void onSlicedConditionMayChange(const uint64_t timestamp) = 0;
virtual void onConditionChanged(bool condition, const uint64_t timestamp) = 0;
@@ -75,11 +82,13 @@ public:
protected:
sp<ConditionWizard> mWizard;
- int mConditionTrackerIndex;
+ const int mConditionTrackerIndex;
- uint64_t mCurrentBucketStartTimeNs;
+ const int64_t mBucketSizeNs;
+
+ const bool mNested;
- int64_t mBucketSizeNs;
+ uint64_t mCurrentBucketStartTimeNs;
std::vector<DurationBucket>& mBucket; // where to write output
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 43c21a830ecf..8c7bfb6e4462 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -23,10 +23,10 @@ namespace android {
namespace os {
namespace statsd {
-MaxDurationTracker::MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+MaxDurationTracker::MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
std::vector<DurationBucket>& bucket)
- : DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket) {
+ : DurationTracker(wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs, bucket) {
}
void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
@@ -38,10 +38,10 @@ void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool conditi
switch (duration.state) {
case kStarted:
- // The same event is already started. Because we are not counting nesting, so ignore.
+ duration.startCount++;
break;
case kPaused:
- // Safe to do nothing here. Paused means started but condition is false.
+ duration.startCount++;
break;
case kStopped:
if (!condition) {
@@ -51,11 +51,13 @@ void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool conditi
duration.state = DurationState::kStarted;
duration.lastStartTime = eventTime;
}
+ duration.startCount = 1;
break;
}
}
-void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime) {
+void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
+ bool forceStop) {
VLOG("MaxDuration: key %s stop", key.c_str());
if (mInfos.find(key) == mInfos.end()) {
// we didn't see a start event before. do nothing.
@@ -68,16 +70,23 @@ void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_
// already stopped, do nothing.
break;
case DurationState::kStarted: {
- duration.state = DurationState::kStopped;
- int64_t durationTime = eventTime - duration.lastStartTime;
- VLOG("Max, key %s, Stop %lld %lld %lld", key.c_str(), (long long)duration.lastStartTime,
- (long long)eventTime, (long long)durationTime);
- duration.lastDuration = duration.lastDuration + durationTime;
- VLOG(" record duration: %lld ", (long long)duration.lastDuration);
+ duration.startCount--;
+ if (forceStop || !mNested || duration.startCount <= 0) {
+ duration.state = DurationState::kStopped;
+ int64_t durationTime = eventTime - duration.lastStartTime;
+ VLOG("Max, key %s, Stop %lld %lld %lld", key.c_str(),
+ (long long)duration.lastStartTime, (long long)eventTime,
+ (long long)durationTime);
+ duration.lastDuration = duration.lastDuration + durationTime;
+ VLOG(" record duration: %lld ", (long long)duration.lastDuration);
+ }
break;
}
case DurationState::kPaused: {
- duration.state = DurationState::kStopped;
+ duration.startCount--;
+ if (forceStop || !mNested || duration.startCount <= 0) {
+ duration.state = DurationState::kStopped;
+ }
break;
}
}
@@ -88,11 +97,13 @@ void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_
}
// Once an atom duration ends, we erase it. Next time, if we see another atom event with the
// same name, they are still considered as different atom durations.
- mInfos.erase(key);
+ if (duration.state == DurationState::kStopped) {
+ mInfos.erase(key);
+ }
}
void MaxDurationTracker::noteStopAll(const uint64_t eventTime) {
for (auto& pair : mInfos) {
- noteStop(pair.first, eventTime);
+ noteStop(pair.first, eventTime, true);
}
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index b095884876a8..167f81e414e1 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -28,12 +28,13 @@ namespace statsd {
// they stop or bucket expires.
class MaxDurationTracker : public DurationTracker {
public:
- MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
- void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
+ void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
+ const bool stopAll) override;
void noteStopAll(const uint64_t eventTime) override;
bool flushIfNeeded(uint64_t timestampNs) override;
void onSlicedConditionMayChange(const uint64_t timestamp) override;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index e4f1d2149f7c..faf5ce50b45f 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -20,10 +20,14 @@
namespace android {
namespace os {
namespace statsd {
+
+using std::pair;
+
OringDurationTracker::OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
- uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ bool nesting, uint64_t currentBucketStartNs,
+ uint64_t bucketSizeNs,
std::vector<DurationBucket>& bucket)
- : DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket),
+ : DurationTracker(wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs, bucket),
mStarted(),
mPaused() {
mLastStartTime = 0;
@@ -36,9 +40,9 @@ void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condi
mLastStartTime = eventTime;
VLOG("record first start....");
}
- mStarted.insert(key);
+ mStarted[key]++;
} else {
- mPaused.insert(key);
+ mPaused[key]++;
}
if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
@@ -48,11 +52,16 @@ void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condi
VLOG("Oring: %s start, condition %d", key.c_str(), condition);
}
-void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp) {
+void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp,
+ const bool stopAll) {
VLOG("Oring: %s stop", key.c_str());
auto it = mStarted.find(key);
if (it != mStarted.end()) {
- mStarted.erase(it);
+ (it->second)--;
+ if (stopAll || !mNested || it->second <= 0) {
+ mStarted.erase(it);
+ mConditionKeyMap.erase(key);
+ }
if (mStarted.empty()) {
mDuration += (timestamp - mLastStartTime);
VLOG("record duration %lld, total %lld ", (long long)timestamp - mLastStartTime,
@@ -60,8 +69,14 @@ void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint6
}
}
- mPaused.erase(key);
- mConditionKeyMap.erase(key);
+ auto pausedIt = mPaused.find(key);
+ if (pausedIt != mPaused.end()) {
+ (pausedIt->second)--;
+ if (stopAll || !mNested || pausedIt->second <= 0) {
+ mPaused.erase(pausedIt);
+ mConditionKeyMap.erase(key);
+ }
+ }
}
void OringDurationTracker::noteStopAll(const uint64_t timestamp) {
if (!mStarted.empty()) {
@@ -118,11 +133,11 @@ bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
}
void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
- vector<HashableDimensionKey> startedToPaused;
- vector<HashableDimensionKey> pausedToStarted;
+ vector<pair<HashableDimensionKey, int>> startedToPaused;
+ vector<pair<HashableDimensionKey, int>> pausedToStarted;
if (!mStarted.empty()) {
for (auto it = mStarted.begin(); it != mStarted.end();) {
- auto key = *it;
+ const auto& key = it->first;
if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
VLOG("Key %s dont have condition key", key.c_str());
++it;
@@ -130,8 +145,8 @@ void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp)
}
if (mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key]) !=
ConditionState::kTrue) {
+ startedToPaused.push_back(*it);
it = mStarted.erase(it);
- startedToPaused.push_back(key);
VLOG("Key %s started -> paused", key.c_str());
} else {
++it;
@@ -147,7 +162,7 @@ void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp)
if (!mPaused.empty()) {
for (auto it = mPaused.begin(); it != mPaused.end();) {
- auto key = *it;
+ const auto& key = it->first;
if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
VLOG("Key %s dont have condition key", key.c_str());
++it;
@@ -155,8 +170,8 @@ void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp)
}
if (mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key]) ==
ConditionState::kTrue) {
+ pausedToStarted.push_back(*it);
it = mPaused.erase(it);
- pausedToStarted.push_back(key);
VLOG("Key %s paused -> started", key.c_str());
} else {
++it;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index b54dafaa1758..78760ba1a024 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -27,12 +27,13 @@ namespace statsd {
// Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
class OringDurationTracker : public DurationTracker {
public:
- OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
- void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
+ void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
+ const bool stopAll) override;
void noteStopAll(const uint64_t eventTime) override;
void onSlicedConditionMayChange(const uint64_t timestamp) override;
void onConditionChanged(bool condition, const uint64_t timestamp) override;
@@ -44,8 +45,8 @@ private:
// 2) which keys are paused (started but condition was false)
// 3) whenever a key stops, we remove it from the started set. And if the set becomes empty,
// it means everything has stopped, we then record the end time.
- std::set<HashableDimensionKey> mStarted;
- std::set<HashableDimensionKey> mPaused;
+ std::map<HashableDimensionKey, int> mStarted;
+ std::map<HashableDimensionKey, int> mPaused;
int64_t mLastStartTime;
std::map<HashableDimensionKey, ConditionKey> mConditionKeyMap;
};
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index c2044d85ec9f..d83c144d5d8b 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -220,6 +220,11 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> countProducer =
@@ -247,6 +252,8 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
const auto& simpleCondition = durationWhat.simple_condition();
+ bool nesting = simpleCondition.count_nesting();
+
int trackerIndices[3] = {-1, -1, -1};
if (!simpleCondition.has_start() ||
!handleMetricWithLogTrackers(simpleCondition.start(), metricIndex,
@@ -276,15 +283,20 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
int conditionIndex = -1;
- if (metric.has_predicate()) {
- handleMetricWithConditions(metric.predicate(), metricIndex, conditionTrackerMap,
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> durationMetric = new DurationMetricProducer(
metric, conditionIndex, trackerIndices[0], trackerIndices[1], trackerIndices[2],
- wizard, internalDimension, startTimeNs);
+ nesting, wizard, internalDimension, startTimeNs);
allMetricProducers.push_back(durationMetric);
}
@@ -308,6 +320,11 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> eventMetric =
@@ -349,6 +366,11 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> valueProducer =
@@ -389,6 +411,11 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> gaugeProducer =
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 13e776fb1f80..5aa3db573c70 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 239881402880..6c32d3e1b11e 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, versionCode 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index de68fbceb7a9..24eb96619527 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
deleted file mode 100644
index 898856b06ebc..000000000000
--- a/cmds/statsd/src/stats_events_copy.proto
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * 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.
- */
-
-// STOPSHIP: this is a duplicate of stats_event.proto with LITE_RUNTIME added
-// to produce device side lite proto. We should move statsd to soong so that
-// we can generate full and lite library from the same proto file.
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-// TODO: Not the right package and class name
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_outer_classname = "StatsEventProto";
-
-/**
- * The master event class. This message defines all of the available
- * raw stats log events from the Android system, also known as "atoms."
- *
- * This field contains a single oneof with all of the available messages.
- * The stats-log-api-gen tool runs as part of the Android build and
- * generates the android.util.StatsLog class, which contains the constants
- * and methods that Android uses to log.
- *
- * This StatsEvent class is not actually built into the Android system.
- * Instead, statsd on Android constructs these messages synthetically,
- * in the format defined here and in stats_log.proto.
- */
-message StatsEvent {
- oneof event {
- // 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;
- DeviceTemperatureReported device_temperature_reported = 33;
- // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
- }
-}
-
-/**
- * A WorkSource represents the chained attribution of applications that
- * resulted in a particular bit of work being done.
- */
-message WorkSource {
- // TODO
-}
-
-/*
- * *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd
- * and Westworld.
- *
- * RULES:
- * - The field ids for each atom must start at 1, and count upwards by 1.
- * Skipping field ids is not allowed.
- * - These form an API, so renaming, renumbering or removing fields is
- * not allowed between android releases. (This is not currently enforced,
- * but there will be a tool to enforce this restriction).
- * - The types must be built-in protocol buffer types, namely, no sub-messages
- * are allowed (yet). The bytes type is also not allowed.
- * - The CamelCase name of the message type should match the
- * underscore_separated name as defined in StatsEvent.
- * - If an atom represents work that can be attributed to an app, there can
- * be exactly one WorkSource field. It must be field number 1.
- * - A field that is a uid should be a string field, tagged with the [xxx]
- * annotation. The generated code on android will be represented by UIDs,
- * and those UIDs will be translated in xxx to those strings.
- *
- * CONVENTIONS:
- * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
- * - If there is a UID, it goes first. Think in an object-oriented fashion.
- * *****************************************************************************
- */
-
-/**
- * Logs the temperature of the device, in tenths of a degree Celsius.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message DeviceTemperatureReported {
- // Temperature in tenths of a degree C.
- optional int32 temperature = 1;
-}
-
-/**
- * Logs when the screen state changes.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScreenStateChanged {
- // TODO: Use the real screen state.
- enum State {
- STATE_UNKNOWN = 0;
- STATE_OFF = 1;
- STATE_ON = 2;
- STATE_DOZE = 3;
- STATE_DOZE_SUSPEND = 4;
- STATE_VR = 5;
- }
- // New screen state.
- optional State display_state = 1;
-}
-
-/**
- * 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 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 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 {
- // 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: 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 1e37ff8c0aef..4f5df5512847 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -22,7 +22,7 @@ package android.os.statsd;
option java_package = "com.android.os";
option java_outer_classname = "StatsLog";
-import "frameworks/base/cmds/statsd/src/stats_events_copy.proto";
+import "frameworks/base/cmds/statsd/src/atoms_copy.proto";
message KeyValuePair {
optional int32 key = 1;
@@ -38,7 +38,7 @@ message KeyValuePair {
message EventMetricData {
optional int64 timestamp_nanos = 1;
- optional StatsEvent stats_events = 2;
+ optional Atom atom = 2;
}
message CountBucketInfo {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 7648a9178a7c..d3b04ba5e32d 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -47,6 +47,7 @@ message KeyValueMatcher {
}
enum LogicalOperation {
+ LOGICAL_OPERATION_UNSPECIFIED = 0;
AND = 1;
OR = 2;
NOT = 3;
@@ -111,23 +112,12 @@ message Bucket {
optional int64 bucket_size_millis = 1;
}
-message Alert {
- optional string name = 1;
-
- optional string metric_name = 2;
-
- message IncidentdDetails {
- repeated int32 section = 1;
- }
- optional IncidentdDetails incidentd_details = 3;
-
- optional int32 number_of_buckets = 4;
-
- optional int32 refractory_period_secs = 5;
+message EventConditionLink {
+ optional string condition = 1;
- optional int64 trigger_if_sum_gt = 6;
+ repeated KeyMatcher key_in_main = 2;
- optional int32 refractory_period_in_buckets = 7;
+ repeated KeyMatcher key_in_condition = 3;
}
message EventMetric {
@@ -151,9 +141,7 @@ message CountMetric {
optional Bucket bucket = 5;
- optional bool include_in_output = 6;
-
- repeated EventConditionLink links = 7;
+ repeated EventConditionLink links = 6;
}
message DurationMetric {
@@ -161,20 +149,20 @@ message DurationMetric {
optional string what = 2;
- enum AggregationType {
- DURATION_SUM = 1;
+ optional string condition = 3;
- DURATION_MAX_SPARSE = 2;
- }
- optional AggregationType type = 3;
+ repeated EventConditionLink links = 4;
- optional string predicate = 4;
+ enum AggregationType {
+ SUM = 1;
- repeated KeyMatcher dimension = 5;
+ MAX_SPARSE = 2;
+ }
+ optional AggregationType aggregation_type = 5 [default = SUM];
- optional Bucket bucket = 6;
+ repeated KeyMatcher dimension = 6;
- repeated EventConditionLink links = 7;
+ optional Bucket bucket = 7;
}
message GaugeMetric {
@@ -208,16 +196,30 @@ message ValueMetric {
repeated EventConditionLink links = 7;
- enum Operation { SUM = 1; }
- optional Operation operation = 9 [default = SUM];
+ enum AggregationType {
+ SUM = 1;
+ }
+ optional AggregationType aggregation_type = 8 [default = SUM];
}
-message EventConditionLink {
- optional string condition = 1;
+message Alert {
+ optional string name = 1;
- repeated KeyMatcher key_in_main = 2;
- repeated KeyMatcher key_in_condition = 3;
-};
+ optional string metric_name = 2;
+
+ message IncidentdDetails {
+ repeated int32 section = 1;
+ }
+ optional IncidentdDetails incidentd_details = 3;
+
+ optional int32 number_of_buckets = 4;
+
+ optional int32 refractory_period_secs = 5;
+
+ optional int64 trigger_if_sum_gt = 6;
+
+ optional int32 refractory_period_in_buckets = 7;
+}
message StatsdConfig {
optional string name = 1;
@@ -236,5 +238,5 @@ message StatsdConfig {
repeated Condition condition = 8;
- repeated Alert alerts = 9;
+ repeated Alert alert = 9;
}
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index fad5de67ca1a..f570522dcd0a 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -85,7 +85,7 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
// TODO: Remove this when we get rid of the fake one, and make this
// test loading one from disk somewhere.
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq("12345")))
+ OnConfigUpdated(ConfigKeyEq(1000, "fake"), StatsdConfigEq("12345")))
.RetiresOnSaturation();
manager->Startup();
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index d0898b0fa865..40c0e9d74c1d 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -27,7 +27,7 @@ using namespace android::os::statsd;
using std::unordered_map;
using std::vector;
-const int TAG_ID = 123;
+const int32_t TAG_ID = 123;
const int FIELD_ID_1 = 1;
const int FIELD_ID_2 = 2;
const int FIELD_ID_3 = 2;
@@ -43,8 +43,6 @@ TEST(LogEntryMatcherTest, TestSimpleMatcher) {
simpleMatcher->set_tag(TAG_ID);
LogEvent event(TAG_ID, 0);
-
- // Convert to a LogEvent
event.init();
// Test
@@ -63,10 +61,8 @@ TEST(LogEntryMatcherTest, TestBoolMatcher) {
// Set up the event
LogEvent event(TAG_ID, 0);
- auto list = event.GetAndroidLogEventList();
- *list << true;
- *list << false;
-
+ event.write(true);
+ event.write(false);
// Convert to a LogEvent
event.init();
@@ -99,14 +95,44 @@ TEST(LogEntryMatcherTest, TestStringMatcher) {
// Set up the event
LogEvent event(TAG_ID, 0);
- auto list = event.GetAndroidLogEventList();
- *list << "some value";
+ event.write("some value");
+ // Convert to a LogEvent
+ event.init();
+
+ // Test
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+}
+
+TEST(LogEntryMatcherTest, TestMultiFieldsMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->set_tag(TAG_ID);
+ auto keyValue1 = simpleMatcher->add_key_value_matcher();
+ keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
+ auto keyValue2 = simpleMatcher->add_key_value_matcher();
+ keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
+
+ // Set up the event
+ LogEvent event(TAG_ID, 0);
+ event.write(2);
+ event.write(3);
// Convert to a LogEvent
event.init();
// Test
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(3);
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(4);
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+ keyValue1->set_eq_int(4);
+ keyValue2->set_eq_int(3);
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
}
TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
@@ -120,9 +146,7 @@ TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
// Set up the event
LogEvent event(TAG_ID, 0);
- auto list = event.GetAndroidLogEventList();
- *list << 11;
-
+ event.write(11);
event.init();
// Test
@@ -168,8 +192,6 @@ TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
}
-#if 0
-
TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
// Set up the matcher
LogEntryMatcher matcher;
@@ -179,22 +201,28 @@ TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
- LogEvent event;
- event.tagId = TAG_ID;
-
+ LogEvent event1(TAG_ID, 0);
keyValue->set_lt_float(10.0);
- event.floatMap[FIELD_ID_1] = 10.1;
- EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
- event.floatMap[FIELD_ID_1] = 9.9;
- EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
-
+ event1.write(10.1f);
+ event1.init();
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event1));
+
+ LogEvent event2(TAG_ID, 0);
+ event2.write(9.9f);
+ event2.init();
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, event2));
+
+ LogEvent event3(TAG_ID, 0);
+ event3.write(10.1f);
+ event3.init();
keyValue->set_gt_float(10.0);
- event.floatMap[FIELD_ID_1] = 10.1;
- EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
- event.floatMap[FIELD_ID_1] = 9.9;
- EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, event3));
+
+ LogEvent event4(TAG_ID, 0);
+ event4.write(9.9f);
+ event4.init();
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event4));
}
-#endif
// Helper for the composite matchers.
void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, int val) {
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index c64719ee0c85..4c12b0397769 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -36,10 +36,9 @@ TEST(UidMapTest, TestIsolatedUID) {
sp<UidMap> m = new UidMap();
StatsLogProcessor p(m, nullptr);
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
- android_log_event_list* list = addEvent.GetAndroidLogEventList();
- *list << 100; // parent UID
- *list << 101; // isolated UID
- *list << 1; // Indicates creation.
+ addEvent.write(100); // parent UID
+ addEvent.write(101); // isolated UID
+ addEvent.write(1); // Indicates creation.
addEvent.init();
EXPECT_EQ(101, m->getParentUidOrSelf(101));
@@ -48,10 +47,9 @@ TEST(UidMapTest, TestIsolatedUID) {
EXPECT_EQ(100, m->getParentUidOrSelf(101));
LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
- list = removeEvent.GetAndroidLogEventList();
- *list << 100; // parent UID
- *list << 101; // isolated UID
- *list << 0; // Indicates removal.
+ removeEvent.write(100); // parent UID
+ removeEvent.write(101); // isolated UID
+ removeEvent.write(0); // Indicates removal.
removeEvent.init();
p.OnLogEvent(removeEvent);
EXPECT_EQ(101, m->getParentUidOrSelf(101));
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 05aad290e3fe..80a0068690f7 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -46,10 +46,9 @@ SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
}
void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
- auto list = event->GetAndroidLogEventList();
- *list << uid; // uid
- *list << wl;
- *list << acquire;
+ event->write(uid); // uid
+ event->write(wl);
+ event->write(acquire);
event->init();
}
@@ -108,6 +107,18 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
+ // match nothing.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
// the case for match stop.
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index d07a84d4c3d8..b7c9b406e0b9 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -138,15 +138,13 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
link->add_key_in_condition()->set_key(2);
LogEvent event1(1, bucketStartTimeNs + 1);
- auto list = event1.GetAndroidLogEventList();
- *list << "111"; // uid
+ event1.write("111"); // uid
event1.init();
ConditionKey key1;
key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
LogEvent event2(1, bucketStartTimeNs + 10);
- auto list2 = event2.GetAndroidLogEventList();
- *list2 << "222"; // uid
+ event2.write("222"); // uid
event2.init();
ConditionKey key2;
key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0971d2682d40..18d177cb9173 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -95,15 +95,13 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
link->add_key_in_condition()->set_key(2);
LogEvent event1(1, bucketStartTimeNs + 1);
- auto list = event1.GetAndroidLogEventList();
- *list << "111"; // uid
+ event1.write("111"); // uid
event1.init();
ConditionKey key1;
key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
LogEvent event2(1, bucketStartTimeNs + 10);
- auto list2 = event2.GetAndroidLogEventList();
- *list2 << "222"; // uid
+ event2.write("222"); // uid
event2.init();
ConditionKey key2;
key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 58bf1b30a9d0..9cc184a1a435 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -45,13 +45,13 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(wizard, -1, bucketStartTimeNs, bucketSizeNs, buckets);
+ MaxDurationTracker tracker(wizard, -1, false, bucketStartTimeNs, bucketSizeNs, buckets);
tracker.noteStart("", true, bucketStartTimeNs, key1);
- tracker.noteStop("", bucketStartTimeNs + 10);
+ tracker.noteStop("", bucketStartTimeNs + 10, false);
tracker.noteStart("", true, bucketStartTimeNs + 20, key1);
- tracker.noteStop("", bucketStartTimeNs + 40);
+ tracker.noteStop("", bucketStartTimeNs + 40, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
@@ -67,7 +67,7 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(wizard, -1, bucketStartTimeNs, bucketSizeNs, buckets);
+ MaxDurationTracker tracker(wizard, -1, false, bucketStartTimeNs, bucketSizeNs, buckets);
tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
@@ -77,6 +77,37 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
EXPECT_EQ((long long)bucketSizeNs, buckets[1].mDuration);
}
+TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ vector<DurationBucket> buckets;
+ ConditionKey key1;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ MaxDurationTracker tracker(wizard, -1, true, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ // 2 starts
+ tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
+ tracker.noteStart("", true, bucketStartTimeNs + 10, key1);
+ // one stop
+ tracker.noteStop("", bucketStartTimeNs + 20, false /*stop all*/);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
+
+ EXPECT_EQ(2u, buckets.size());
+ EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].mDuration);
+ EXPECT_EQ((long long)bucketSizeNs, buckets[1].mDuration);
+
+ // real stop now.
+ tracker.noteStop("", bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
+ tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1);
+
+ EXPECT_EQ(3u, buckets.size());
+ EXPECT_EQ(5, buckets[2].mDuration);
+}
+
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -93,13 +124,13 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- MaxDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+ MaxDurationTracker tracker(wizard, 1, false, bucketStartTimeNs, bucketSizeNs, buckets);
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 74a6f11754f3..f495d6bc24b8 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -47,18 +47,43 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+ OringDurationTracker tracker(wizard, 1, false, bucketStartTimeNs, bucketSizeNs, buckets);
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
}
+TEST(OringDurationTrackerTest, TestDurationNested) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ ConditionKey key1;
+ key1["APP_BACKGROUND"] = "1:maps|";
+
+ vector<DurationBucket> buckets;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ OringDurationTracker tracker(wizard, 1, true, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
+
+ tracker.noteStop("2:maps", eventStartTimeNs + 2000, false);
+ tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(2003, buckets[0].mDuration);
+}
+
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -75,18 +100,50 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+ OringDurationTracker tracker(wizard, 1, false, bucketStartTimeNs, bucketSizeNs, buckets);
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
EXPECT_EQ(5, buckets[0].mDuration);
}
+
+TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ ConditionKey key1;
+ key1["APP_BACKGROUND"] = "1:maps|";
+
+ EXPECT_CALL(*wizard, query(_, key1)) // #4
+ .WillOnce(Return(ConditionState::kFalse));
+
+ vector<DurationBucket> buckets;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ OringDurationTracker tracker(wizard, 1, true, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1);
+
+ tracker.noteStop("2:maps", eventStartTimeNs + 3, false);
+
+ tracker.onSlicedConditionMayChange(eventStartTimeNs + 15);
+
+ tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(15, buckets[0].mDuration);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 72b4194d533e..cd647cb9c238 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -64,9 +64,8 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
- auto list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 11;
+ event->write(1);
+ event->write(11);
event->init();
allData.push_back(event);
@@ -89,9 +88,8 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
allData.clear();
event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
- list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 22;
+ event->write(1);
+ event->write(22);
event->init();
allData.push_back(event);
valueProducer.onDataPulled(allData);
@@ -110,9 +108,8 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
- list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 33;
+ event->write(1);
+ event->write(33);
event->init();
allData.push_back(event);
valueProducer.onDataPulled(allData);
@@ -159,9 +156,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
- auto list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 100;
+ event->write(1);
+ event->write(100);
event->init();
data->push_back(event);
return true;
@@ -174,9 +170,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
- auto list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 120;
+ event->write(1);
+ event->write(120);
event->init();
data->push_back(event);
return true;
@@ -201,9 +196,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
- auto list = event->GetAndroidLogEventList();
- *list << 1;
- *list << 110;
+ event->write(1);
+ event->write(110);
event->init();
allData.push_back(event);
valueProducer.onDataPulled(allData);
@@ -253,14 +247,12 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
bucketStartTimeNs, pullerManager);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
- auto list = event1->GetAndroidLogEventList();
- *list << 1;
- *list << 10;
+ event1->write(1);
+ event1->write(10);
event1->init();
shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
- auto list2 = event2->GetAndroidLogEventList();
- *list2 << 1;
- *list2 << 20;
+ event2->write(1);
+ event2->write(20);
event2->init();
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1, false);
// has one slice