summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/app_process/Android.bp1
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java29
-rw-r--r--cmds/bootanimation/BootAnimation.cpp42
-rw-r--r--cmds/idmap2/Android.bp3
-rw-r--r--cmds/idmap2/idmap2/Create.cpp2
-rw-r--r--cmds/idmap2/idmap2/Dump.cpp2
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp13
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h9
-rw-r--r--cmds/idmap2/include/idmap2/BinaryStreamVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/PrettyPrintVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/RawPrintVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h2
-rw-r--r--cmds/idmap2/libidmap2/ResourceUtils.cpp10
-rw-r--r--cmds/idmap2/libidmap2/ZipFile.cpp1
-rwxr-xr-xcmds/idmap2/static-checks.sh5
-rw-r--r--cmds/idmap2/tests/TestHelpers.h4
-rwxr-xr-xcmds/idmap2/valgrind.sh59
-rw-r--r--cmds/locksettings/TEST_MAPPING2
-rw-r--r--cmds/statsd/Android.bp171
-rw-r--r--cmds/statsd/src/FieldValue.cpp21
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp10
-rw-r--r--cmds/statsd/src/HashableDimensionKey.h9
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h13
-rw-r--r--cmds/statsd/src/StatsService.cpp15
-rw-r--r--cmds/statsd/src/StatsService.h4
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp3
-rw-r--r--cmds/statsd/src/atoms.proto260
-rw-r--r--cmds/statsd/src/condition/StateConditionTracker.cpp (renamed from cmds/statsd/src/condition/StateTracker.cpp)24
-rw-r--r--cmds/statsd/src/condition/StateConditionTracker.h (renamed from cmds/statsd/src/condition/StateTracker.h)12
-rw-r--r--cmds/statsd/src/external/GpuStatsPuller.cpp12
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp25
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp99
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.h48
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp7
-rw-r--r--cmds/statsd/src/logd/LogEvent.h3
-rw-r--r--cmds/statsd/src/main.cpp4
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp5
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h197
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp16
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h2
-rw-r--r--cmds/statsd/src/state/StateListener.h52
-rw-r--r--cmds/statsd/src/state/StateManager.cpp92
-rw-r--r--cmds/statsd/src/state/StateManager.h77
-rw-r--r--cmds/statsd/src/state/StateTracker.cpp159
-rw-r--r--cmds/statsd/src/state/StateTracker.h95
-rw-r--r--cmds/statsd/src/stats_log.proto13
-rw-r--r--cmds/statsd/src/statsd_config.proto34
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp1
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp4
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp312
-rw-r--r--cmds/statsd/tests/condition/StateConditionTracker_test.cpp (renamed from cmds/statsd/tests/condition/StateTracker_test.cpp)6
-rw-r--r--cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp5
-rw-r--r--cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp95
-rw-r--r--cmds/statsd/tests/state/StateTracker_test.cpp356
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java76
55 files changed, 2014 insertions, 540 deletions
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index f92502370566..8be95e4659b4 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -22,7 +22,6 @@ cc_binary {
"libcutils",
"libdl",
"libhidlbase",
- "libhwbinder",
"liblog",
"libnativeloader",
"libutils",
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 76b905d8985f..ed717c491467 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -125,6 +125,11 @@ public class Bmgr {
return;
}
+ if ("autorestore".equals(op)) {
+ doAutoRestore(userId);
+ return;
+ }
+
if ("enabled".equals(op)) {
doEnabled(userId);
return;
@@ -213,6 +218,26 @@ public class Bmgr {
return true;
}
+ private void doAutoRestore(int userId) {
+ String arg = nextArg();
+ if (arg == null) {
+ showUsage();
+ return;
+ }
+
+ try {
+ boolean enable = Boolean.parseBoolean(arg);
+ mBmgr.setAutoRestore(enable);
+ System.out.println(
+ "Auto restore is now "
+ + (enable ? "enabled" : "disabled")
+ + " for user "
+ + userId);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
private String activatedToString(boolean activated) {
return activated ? "activated" : "deactivated";
}
@@ -918,6 +943,7 @@ public class Bmgr {
System.err.println(" bmgr init TRANSPORT...");
System.err.println(" bmgr activate BOOL");
System.err.println(" bmgr activated");
+ System.err.println(" bmgr autorestore BOOL");
System.err.println("");
System.err.println("The '--user' option specifies the user on which the operation is run.");
System.err.println("It must be the first argument before the operation.");
@@ -992,6 +1018,9 @@ public class Bmgr {
System.err.println("");
System.err.println("The 'activated' command reports the current activated/deactivated");
System.err.println("state of the backup mechanism.");
+ System.err.println("");
+ System.err.println("The 'autorestore' command enables or disables automatic restore when");
+ System.err.println("a new package is installed.");
}
private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index db384baff4d7..e1cb7ca6a697 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -288,6 +288,48 @@ status_t BootAnimation::readyToRun() {
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::Transaction t;
+
+ // this guest property specifies multi-display IDs to show the boot animation
+ // multiple ids can be set with comma (,) as separator, for example:
+ // setprop boot.animation.displays 19260422155234049,19261083906282754
+ Vector<uint64_t> physicalDisplayIds;
+ char displayValue[PROPERTY_VALUE_MAX] = "";
+ property_get("boot.animation.displays", displayValue, "");
+ bool isValid = displayValue[0] != '\0';
+ if (isValid) {
+ char *p = displayValue;
+ while (*p) {
+ if (!isdigit(*p) && *p != ',') {
+ isValid = false;
+ break;
+ }
+ p ++;
+ }
+ if (!isValid)
+ SLOGE("Invalid syntax for the value of system prop: boot.animation.displays");
+ }
+ if (isValid) {
+ std::istringstream stream(displayValue);
+ for (PhysicalDisplayId id; stream >> id; ) {
+ physicalDisplayIds.add(id);
+ if (stream.peek() == ',')
+ stream.ignore();
+ }
+
+ // In the case of multi-display, boot animation shows on the specified displays
+ // in addition to the primary display
+ auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ constexpr uint32_t LAYER_STACK = 0;
+ for (auto id : physicalDisplayIds) {
+ if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
+ sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(id);
+ if (token != nullptr)
+ t.setDisplayLayerStack(token, LAYER_STACK);
+ }
+ }
+ t.setLayerStack(control, LAYER_STACK);
+ }
+
t.setLayer(control, 0x40000000)
.apply();
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index d4d587108a54..4c77ba402595 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -69,6 +69,7 @@ cc_library {
static_libs: [
"libandroidfw",
"libbase",
+ "libcutils",
"libutils",
"libziparchive",
],
@@ -121,6 +122,7 @@ cc_test {
static_libs: [
"libandroidfw",
"libbase",
+ "libcutils",
"libidmap2",
"liblog",
"libutils",
@@ -163,6 +165,7 @@ cc_binary {
static_libs: [
"libandroidfw",
"libbase",
+ "libcutils",
"libidmap2",
"liblog",
"libutils",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index bb8d92737563..f482191b09a8 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -50,7 +50,7 @@ Result<Unit> Create(const std::vector<std::string>& args) {
std::string overlay_apk_path;
std::string idmap_path;
std::vector<std::string> policies;
- bool ignore_overlayable;
+ bool ignore_overlayable = false;
const CommandLineOptions opts =
CommandLineOptions("idmap2 create")
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 8716bf313ed0..47f442aab235 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -39,7 +39,7 @@ using android::idmap2::Unit;
Result<Unit> Dump(const std::vector<std::string>& args) {
SYSTRACE << "Dump " << args;
std::string idmap_path;
- bool verbose;
+ bool verbose = false;
const CommandLineOptions opts =
CommandLineOptions("idmap2 dump")
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 0b349e10a118..d0530f2d344e 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -98,6 +98,7 @@ Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector
}
std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
+ // clang-format off
static const std::vector<std::pair<std::string, std::string>> values = {
{"/odm/", kPolicyOdm},
{"/oem/", kPolicyOem},
@@ -106,6 +107,7 @@ std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
{"/system_ext/", kPolicySystem},
{"/vendor/", kPolicyVendor},
};
+ // clang-format on
std::vector<std::string> fulfilled_policies = {kPolicyPublic};
for (auto const& pair : values) {
@@ -176,6 +178,17 @@ Result<Unit> Scan(const std::vector<std::string>& args) {
continue;
}
+ // Note that conditional property enablement/exclusion only applies if
+ // the attribute is present. In its absence, all overlays are presumed enabled.
+ if (!overlay_info->requiredSystemPropertyName.empty()
+ && !overlay_info->requiredSystemPropertyValue.empty()) {
+ // if property set & equal to value, then include overlay - otherwise skip
+ if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "")
+ != overlay_info->requiredSystemPropertyValue) {
+ continue;
+ }
+ }
+
std::vector<std::string> fulfilled_policies;
if (!override_policies.empty()) {
fulfilled_policies = override_policies;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 1aab0598449b..94d2af49260c 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -34,18 +34,19 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
}
binder::Status getIdmapPath(const std::string& overlay_apk_path, int32_t user_id,
- std::string* _aidl_return);
+ std::string* _aidl_return) override;
binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
- bool* _aidl_return);
+ bool* _aidl_return) override;
binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
+ bool enforce_overlayable, int32_t user_id,
+ bool* _aidl_return) override;
binder::Status createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id,
- std::unique_ptr<std::string>* _aidl_return);
+ std::unique_ptr<std::string>* _aidl_return) override;
};
} // namespace android::os
diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
index 2c3e9d321881..1a0d4438f1b3 100644
--- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
+++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
@@ -29,11 +29,12 @@ class BinaryStreamVisitor : public Visitor {
public:
explicit BinaryStreamVisitor(std::ostream& stream) : stream_(stream) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~BinaryStreamVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
void Write16(uint16_t value);
diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
index 5111bb2eaab2..f0f141a3757c 100644
--- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
@@ -33,11 +33,12 @@ class PrettyPrintVisitor : public Visitor {
public:
explicit PrettyPrintVisitor(std::ostream& stream) : stream_(stream) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~PrettyPrintVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
std::ostream& stream_;
diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
index 2e543d4fabdd..cd3897109a32 100644
--- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
@@ -34,11 +34,12 @@ class RawPrintVisitor : public Visitor {
public:
explicit RawPrintVisitor(std::ostream& stream) : stream_(stream), offset_(0) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~RawPrintVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
void print(uint16_t value, const char* fmt, ...);
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 8797a788dd1d..9a0c2abced5a 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -30,6 +30,8 @@ namespace android::idmap2::utils {
struct OverlayManifestInfo {
std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes)
std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string requiredSystemPropertyName; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string requiredSystemPropertyValue; // NOLINT(misc-non-private-member-variables-in-classes)
bool is_static; // NOLINT(misc-non-private-member-variables-in-classes)
int priority = -1; // NOLINT(misc-non-private-member-variables-in-classes)
};
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 71ba3f0f1ac2..dce83e35978d 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -103,6 +103,16 @@ Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
info.priority = std::stoi(iter->second);
}
+ iter = tag->find("requiredSystemPropertyName");
+ if (iter != tag->end()) {
+ info.requiredSystemPropertyName = iter->second;
+ }
+
+ iter = tag->find("requiredSystemPropertyValue");
+ if (iter != tag->end()) {
+ info.requiredSystemPropertyValue = iter->second;
+ }
+
return info;
}
diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp
index 4f5e3a45f183..1e1a218163f0 100644
--- a/cmds/idmap2/libidmap2/ZipFile.cpp
+++ b/cmds/idmap2/libidmap2/ZipFile.cpp
@@ -34,6 +34,7 @@ std::unique_ptr<const ZipFile> ZipFile::Open(const std::string& path) {
::ZipArchiveHandle handle;
int32_t status = ::OpenArchive(path.c_str(), &handle);
if (status != 0) {
+ ::CloseArchive(handle);
return nullptr;
}
return std::unique_ptr<ZipFile>(new ZipFile(handle));
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 41d3c69540b2..a372abdaa146 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -27,10 +27,11 @@ function _eval()
local red="\e[31m"
local green="\e[32m"
local reset="\e[0m"
+ local output
_log "${green}[ RUN ]${reset} ${label}"
- local output="$(eval "$cmd")"
- if [[ -z "${output}" ]]; then
+ output="$(eval "$cmd" 2>&1)"
+ if [[ $? -eq 0 ]]; then
_log "${green}[ OK ]${reset} ${label}"
return 0
else
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index adea3293534d..a7c2f284e7c5 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -123,7 +123,7 @@ std::string GetTestDataPath();
class Idmap2Tests : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
#ifdef __ANDROID__
tmp_dir_path_ = "/data/local/tmp/idmap2-tests-XXXXXX";
#else
@@ -136,7 +136,7 @@ class Idmap2Tests : public testing::Test {
idmap_path_ = tmp_dir_path_ + "/a.idmap";
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_EQ(rmdir(tmp_dir_path_.c_str()), 0)
<< "Failed to remove temporary directory " << tmp_dir_path_ << ": " << strerror(errno);
}
diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh
new file mode 100755
index 000000000000..b4ebab0c7ffe
--- /dev/null
+++ b/cmds/idmap2/valgrind.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+#
+
+function _log()
+{
+ echo -e "$*" >&2
+}
+
+function _eval()
+{
+ local label="$1"
+ local cmd="$2"
+ local red="\e[31m"
+ local green="\e[32m"
+ local reset="\e[0m"
+ local output
+
+ _log "${green}[ RUN ]${reset} ${label}"
+ output="$(eval "$cmd" 2>&1)"
+ if [[ $? -eq 0 ]]; then
+ _log "${green}[ OK ]${reset} ${label}"
+ return 0
+ else
+ echo "${output}"
+ _log "${red}[ FAILED ]${reset} ${label}"
+ errors=$((errors + 1))
+ return 1
+ fi
+}
+
+errors=0
+script="$(readlink -f "$BASH_SOURCE")"
+prefix="$(dirname "$script")"
+target_path="${prefix}/tests/data/target/target.apk"
+overlay_path="${prefix}/tests/data/overlay/overlay.apk"
+idmap_path="/tmp/a.idmap"
+valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full"
+
+_eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path"
+_eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path"
+_eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1"
+_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public"
+_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path"
+_eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests"
+exit $errors
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
index c1cba5f7f22d..56f5cc034f05 100644
--- a/cmds/locksettings/TEST_MAPPING
+++ b/cmds/locksettings/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-devicepolicy": [
{
"name": "CtsDevicePolicyManagerTestCases",
"options": [
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 19fa64073183..cb2732561b56 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -51,11 +51,6 @@ cc_defaults {
srcs: [
":statsd_aidl",
"src/active_config_list.proto",
- "src/statsd_config.proto",
- "src/uid_data.proto",
- "src/FieldValue.cpp",
- "src/hash.cpp",
- "src/stats_log_util.cpp",
"src/anomaly/AlarmMonitor.cpp",
"src/anomaly/AlarmTracker.cpp",
"src/anomaly/AnomalyTracker.cpp",
@@ -63,51 +58,59 @@ cc_defaults {
"src/anomaly/subscriber_util.cpp",
"src/condition/CombinationConditionTracker.cpp",
"src/condition/condition_util.cpp",
- "src/condition/SimpleConditionTracker.cpp",
"src/condition/ConditionWizard.cpp",
- "src/condition/StateTracker.cpp",
+ "src/condition/SimpleConditionTracker.cpp",
+ "src/condition/StateConditionTracker.cpp",
"src/config/ConfigKey.cpp",
"src/config/ConfigListener.cpp",
"src/config/ConfigManager.cpp",
"src/external/GpuStatsPuller.cpp",
"src/external/Perfetto.cpp",
- "src/external/StatsPuller.cpp",
+ "src/external/PowerStatsPuller.cpp",
+ "src/external/puller_util.cpp",
+ "src/external/ResourceHealthManagerPuller.cpp",
"src/external/StatsCallbackPuller.cpp",
"src/external/StatsCompanionServicePuller.cpp",
+ "src/external/StatsPuller.cpp",
+ "src/external/StatsPullerManager.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
- "src/external/PowerStatsPuller.cpp",
- "src/external/ResourceHealthManagerPuller.cpp",
+ "src/external/SurfaceflingerStatsPuller.cpp",
"src/external/TrainInfoPuller.cpp",
- "src/external/StatsPullerManager.cpp",
- "src/external/puller_util.cpp",
+ "src/FieldValue.cpp",
+ "src/guardrail/StatsdStats.cpp",
+ "src/hash.cpp",
+ "src/HashableDimensionKey.cpp",
"src/logd/LogEvent.cpp",
"src/logd/LogEventQueue.cpp",
"src/matchers/CombinationLogMatchingTracker.cpp",
"src/matchers/EventMatcherWizard.cpp",
"src/matchers/matcher_util.cpp",
"src/matchers/SimpleLogMatchingTracker.cpp",
- "src/metrics/MetricProducer.cpp",
- "src/metrics/EventMetricProducer.cpp",
"src/metrics/CountMetricProducer.cpp",
- "src/metrics/DurationMetricProducer.cpp",
- "src/metrics/duration_helper/OringDurationTracker.cpp",
"src/metrics/duration_helper/MaxDurationTracker.cpp",
- "src/metrics/ValueMetricProducer.cpp",
+ "src/metrics/duration_helper/OringDurationTracker.cpp",
+ "src/metrics/DurationMetricProducer.cpp",
+ "src/metrics/EventMetricProducer.cpp",
"src/metrics/GaugeMetricProducer.cpp",
- "src/metrics/MetricsManager.cpp",
+ "src/metrics/MetricProducer.cpp",
"src/metrics/metrics_manager_util.cpp",
+ "src/metrics/MetricsManager.cpp",
+ "src/metrics/ValueMetricProducer.cpp",
"src/packages/UidMap.cpp",
- "src/storage/StorageManager.cpp",
+ "src/shell/shell_config.proto",
+ "src/shell/ShellSubscriber.cpp",
+ "src/socket/StatsSocketListener.cpp",
+ "src/state/StateManager.cpp",
+ "src/state/StateTracker.cpp",
+ "src/stats_log_util.cpp",
+ "src/statscompanion_util.cpp",
+ "src/statsd_config.proto",
"src/StatsLogProcessor.cpp",
"src/StatsService.cpp",
- "src/statscompanion_util.cpp",
+ "src/storage/StorageManager.cpp",
"src/subscriber/IncidentdReporter.cpp",
"src/subscriber/SubscriberReporter.cpp",
- "src/HashableDimensionKey.cpp",
- "src/guardrail/StatsdStats.cpp",
- "src/socket/StatsSocketListener.cpp",
- "src/shell/ShellSubscriber.cpp",
- "src/shell/shell_config.proto",
+ "src/uid_data.proto",
],
local_include_dirs: [
@@ -120,23 +123,25 @@ cc_defaults {
],
shared_libs: [
+ "android.frameworks.stats@1.0",
+ "android.hardware.health@2.0",
+ "android.hardware.power.stats@1.0",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
"libbase",
"libbinder",
+ "libcutils",
"libgraphicsenv",
+ "libhidlbase",
"libincident",
"liblog",
- "libutils",
- "libservices",
"libprotoutil",
+ "libservices",
"libstatslog",
- "libhidlbase",
- "android.frameworks.stats@1.0",
- "android.hardware.health@2.0",
- "android.hardware.power@1.0",
- "android.hardware.power@1.1",
- "android.hardware.power.stats@1.0",
+ "libstatssocket",
"libsysutils",
- "libcutils",
+ "libtimestats_proto",
+ "libutils",
],
}
@@ -204,56 +209,62 @@ cc_test {
],
srcs: [
+ // atom_field_options.proto needs field_options.proto, but that is
+ // not included in libprotobuf-cpp-lite, so compile it here.
+ ":libprotobuf-internal-protos",
+
"src/atom_field_options.proto",
"src/atoms.proto",
- "src/stats_log.proto",
"src/shell/shell_data.proto",
+ "src/stats_log.proto",
"tests/AlarmMonitor_test.cpp",
"tests/anomaly/AlarmTracker_test.cpp",
"tests/anomaly/AnomalyTracker_test.cpp",
+ "tests/condition/CombinationConditionTracker_test.cpp",
+ "tests/condition/ConditionTimer_test.cpp",
+ "tests/condition/SimpleConditionTracker_test.cpp",
+ "tests/condition/StateConditionTracker_test.cpp",
"tests/ConfigManager_test.cpp",
- "tests/external/puller_util_test.cpp",
+ "tests/e2e/Alarm_e2e_test.cpp",
+ "tests/e2e/Anomaly_count_e2e_test.cpp",
+ "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
+ "tests/e2e/Attribution_e2e_test.cpp",
+ "tests/e2e/ConfigTtl_e2e_test.cpp",
+ "tests/e2e/DurationMetric_e2e_test.cpp",
+ "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
+ "tests/e2e/GaugeMetric_e2e_push_test.cpp",
+ "tests/e2e/MetricActivation_e2e_test.cpp",
+ "tests/e2e/MetricConditionLink_e2e_test.cpp",
+ "tests/e2e/PartialBucket_e2e_test.cpp",
+ "tests/e2e/ValueMetric_pull_e2e_test.cpp",
+ "tests/e2e/WakelockDuration_e2e_test.cpp",
"tests/external/GpuStatsPuller_test.cpp",
"tests/external/IncidentReportArgs_test.cpp",
+ "tests/external/puller_util_test.cpp",
"tests/external/StatsPuller_test.cpp",
+ "tests/external/SurfaceflingerStatsPuller_test.cpp",
+ "tests/FieldValue_test.cpp",
+ "tests/guardrail/StatsdStats_test.cpp",
"tests/indexed_priority_queue_test.cpp",
+ "tests/log_event/LogEventQueue_test.cpp",
"tests/LogEntryMatcher_test.cpp",
"tests/LogEvent_test.cpp",
- "tests/log_event/LogEventQueue_test.cpp",
- "tests/MetricsManager_test.cpp",
- "tests/StatsLogProcessor_test.cpp",
- "tests/StatsService_test.cpp",
- "tests/UidMap_test.cpp",
- "tests/FieldValue_test.cpp",
- "tests/condition/CombinationConditionTracker_test.cpp",
- "tests/condition/SimpleConditionTracker_test.cpp",
- "tests/condition/StateTracker_test.cpp",
- "tests/condition/ConditionTimer_test.cpp",
- "tests/metrics/OringDurationTracker_test.cpp",
- "tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/CountMetricProducer_test.cpp",
"tests/metrics/DurationMetricProducer_test.cpp",
"tests/metrics/EventMetricProducer_test.cpp",
- "tests/metrics/ValueMetricProducer_test.cpp",
"tests/metrics/GaugeMetricProducer_test.cpp",
- "tests/guardrail/StatsdStats_test.cpp",
+ "tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/metrics_test_helper.cpp",
+ "tests/metrics/OringDurationTracker_test.cpp",
+ "tests/metrics/ValueMetricProducer_test.cpp",
+ "tests/MetricsManager_test.cpp",
+ "tests/shell/ShellSubscriber_test.cpp",
+ "tests/state/StateTracker_test.cpp",
"tests/statsd_test_util.cpp",
+ "tests/StatsLogProcessor_test.cpp",
+ "tests/StatsService_test.cpp",
"tests/storage/StorageManager_test.cpp",
- "tests/e2e/WakelockDuration_e2e_test.cpp",
- "tests/e2e/MetricActivation_e2e_test.cpp",
- "tests/e2e/MetricConditionLink_e2e_test.cpp",
- "tests/e2e/Alarm_e2e_test.cpp",
- "tests/e2e/Attribution_e2e_test.cpp",
- "tests/e2e/GaugeMetric_e2e_push_test.cpp",
- "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
- "tests/e2e/ValueMetric_pull_e2e_test.cpp",
- "tests/e2e/Anomaly_count_e2e_test.cpp",
- "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
- "tests/e2e/ConfigTtl_e2e_test.cpp",
- "tests/e2e/PartialBucket_e2e_test.cpp",
- "tests/e2e/DurationMetric_e2e_test.cpp",
- "tests/shell/ShellSubscriber_test.cpp",
+ "tests/UidMap_test.cpp",
],
static_libs: [
@@ -262,11 +273,11 @@ cc_test {
],
proto: {
- type: "full",
+ type: "lite",
include_dirs: ["external/protobuf/src"],
},
- shared_libs: ["libprotobuf-cpp-full"],
+ shared_libs: ["libprotobuf-cpp-lite"],
}
@@ -279,21 +290,25 @@ cc_benchmark {
defaults: ["statsd_defaults"],
srcs: [
- "src/atom_field_options.proto",
- "src/atoms.proto",
- "src/stats_log.proto",
- "benchmark/main.cpp",
- "benchmark/hello_world_benchmark.cpp",
- "benchmark/log_event_benchmark.cpp",
- "benchmark/stats_write_benchmark.cpp",
+ // atom_field_options.proto needs field_options.proto, but that is
+ // not included in libprotobuf-cpp-lite, so compile it here.
+ ":libprotobuf-internal-protos",
+
+ "benchmark/duration_metric_benchmark.cpp",
"benchmark/filter_value_benchmark.cpp",
"benchmark/get_dimensions_for_condition_benchmark.cpp",
+ "benchmark/hello_world_benchmark.cpp",
+ "benchmark/log_event_benchmark.cpp",
+ "benchmark/main.cpp",
"benchmark/metric_util.cpp",
- "benchmark/duration_metric_benchmark.cpp",
+ "benchmark/stats_write_benchmark.cpp",
+ "src/atom_field_options.proto",
+ "src/atoms.proto",
+ "src/stats_log.proto",
],
proto: {
- type: "full",
+ type: "lite",
include_dirs: ["external/protobuf/src"],
},
@@ -315,7 +330,7 @@ cc_benchmark {
shared_libs: [
"libgtest_prod",
"libstatslog",
- "libprotobuf-cpp-full",
+ "libprotobuf-cpp-lite",
],
}
@@ -329,11 +344,11 @@ java_library {
},
srcs: [
- "src/stats_log.proto",
- "src/statsd_config.proto",
"src/atoms.proto",
"src/shell/shell_config.proto",
"src/shell/shell_data.proto",
+ "src/stats_log.proto",
+ "src/statsd_config.proto",
],
static_libs: [
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 1185127ab805..84a06070e431 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -116,28 +116,13 @@ void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* ou
}
bool isAttributionUidField(const FieldValue& value) {
- int field = value.mField.getField() & 0xff007f;
- if (field == 0x10001 && value.mValue.getType() == INT) {
- return true;
- }
- return false;
+ return isAttributionUidField(value.mField, value.mValue);
}
int32_t getUidIfExists(const FieldValue& value) {
- bool isUid = false;
// the field is uid field if the field is the uid field in attribution node or marked as
// is_uid in atoms.proto
- if (isAttributionUidField(value)) {
- isUid = true;
- } else {
- auto it = android::util::AtomsInfo::kAtomsWithUidField.find(value.mField.getTag());
- if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
- int uidField = it->second; // uidField is the field number in proto
- isUid = value.mField.getDepth() == 0 && value.mField.getPosAtDepth(0) == uidField &&
- value.mValue.getType() == INT;
- }
- }
-
+ bool isUid = isAttributionUidField(value) || isUidField(value.mField, value.mValue);
return isUid ? value.mValue.int_value : -1;
}
@@ -153,7 +138,7 @@ bool isUidField(const Field& field, const Value& value) {
auto it = android::util::AtomsInfo::kAtomsWithUidField.find(field.getTag());
if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
- int uidField = it->second;
+ int uidField = it->second; // uidField is the field number in proto
return field.getDepth() == 0 && field.getPosAtDepth(0) == uidField &&
value.getType() == INT;
}
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index af8b3af6ea61..5e156bb26caa 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -59,6 +59,16 @@ android::hash_t hashDimension(const HashableDimensionKey& value) {
return JenkinsHashWhiten(hash);
}
+bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, Value* output) {
+ for (const auto& value : values) {
+ if (value.mField.matches(matcherField)) {
+ (*output) = value.mValue;
+ return true;
+ }
+ }
+ return false;
+}
+
bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
HashableDimensionKey* output) {
size_t num_matches = 0;
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 6f4941f717ee..a12385057585 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -120,6 +120,13 @@ class MetricDimensionKey {
android::hash_t hashDimension(const HashableDimensionKey& key);
/**
+ * Returns true if a FieldValue field matches the matcher field.
+ * The value of the FieldValue is output.
+ */
+bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
+ Value* output);
+
+/**
* Creating HashableDimensionKeys from FieldValues using matcher.
*
* This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
@@ -169,4 +176,4 @@ struct hash<MetricDimensionKey> {
return android::JenkinsHashWhiten(hash);
}
};
-} // namespace std \ No newline at end of file
+} // namespace std
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f0db1b0128a1..3d002d2efdd0 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -248,19 +248,6 @@ private:
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
-
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1c7180ffbde1..b665a8b99fbd 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -266,7 +266,9 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
IResultReceiver::asInterface(data.readStrongBinder());
err = command(in, out, err, args, resultReceiver);
- resultReceiver->send(err);
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(err);
+ }
return NO_ERROR;
}
default: { return BnStatsManager::onTransact(code, data, reply, flags); }
@@ -411,13 +413,20 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
return cmd_trigger_active_config_broadcast(out, args);
}
if (!args[0].compare(String8("data-subscribe"))) {
- if (mShellSubscriber == nullptr) {
- mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
+ {
+ std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
+ if (mShellSubscriber == nullptr) {
+ mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
+ }
}
int timeoutSec = -1;
if (argCount >= 2) {
timeoutSec = atoi(args[1].c_str());
}
+ if (resultReceiver == nullptr) {
+ ALOGI("Null resultReceiver given, no subscription will be started");
+ return UNEXPECTED_NULL;
+ }
mShellSubscriber->startNewSubscription(in, out, resultReceiver, timeoutSec);
return NO_ERROR;
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 53b6ce989195..949094871936 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -432,6 +432,10 @@ private:
sp<ShellSubscriber> mShellSubscriber;
+ /**
+ * Mutex for setting the shell subscriber
+ */
+ mutable mutex mShellSubscriberMutex;
std::shared_ptr<LogEventQueue> mEventQueue;
FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index d1dcb5df7838..7ace44eef564 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -24,6 +24,7 @@
#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
+#include <inttypes.h>
#include <statslog.h>
#include <time.h>
@@ -224,7 +225,7 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, int64_t metricId
}
if (!mSubscriptions.empty()) {
- ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
+ ALOGI("An anomaly (%" PRId64 ") %s has occurred! Informing subscribers.",
mAlert.id(), key.toString().c_str());
informSubscribers(key, metricId, metricValue);
} else {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b01b0a8e083c..6249de3d3bac 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -334,10 +334,13 @@ message Atom {
BackGesture back_gesture_reported_reported = 224;
UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226;
+ CameraActionEvent camera_action_event = 227;
+ AppCompatibilityChangeReported app_compatibility_change_reported =
+ 228 [(allow_from_any_uid) = true];
}
// Pulled events will start at field 10000.
- // Next: 10062
+ // Next: 10065
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -375,7 +378,6 @@ message Atom {
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
ProcessCpuTime process_cpu_time = 10035;
- NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
OnDevicePowerMeasurement on_device_power_measurement = 10038;
DeviceCalculatedPowerUse device_calculated_power_use = 10039;
@@ -401,11 +403,16 @@ message Atom {
CoolingDevice cooling_device = 10059;
AppOps app_ops = 10060;
ProcessSystemIonHeapSize process_system_ion_heap_size = 10061;
+ SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
+ SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
+ ProcessMemorySnapshot process_memory_snapshot = 10064;
}
// DO NOT USE field numbers above 100,000 in AOSP.
// Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
// Field numbers 200,000 and above are reserved for future use; do not use them at all.
+
+ reserved 10036;
}
/**
@@ -2615,12 +2622,14 @@ message SettingsUIChanged {
message TouchEventReported {
/**
* The fields latency_{min|max|mean|stdev} represent minimum, maximum, mean,
- * and the standard deviation of latency between the kernel and framework
- * for touchscreen events. The units are microseconds.
+ * and the standard deviation of the time spent processing touchscreen events
+ * in the kernel and inputflinger. The units are microseconds.
*
- * The number is measured as the difference between the time at which
- * the input event was received in the evdev driver,
- * and the time at which the input event was received in EventHub.
+ * On supported devices, the starting point is taken during the hard interrupt inside the
+ * kernel touch driver. On all other devices, the starting point is taken inside
+ * the kernel's input event subsystem upon receipt of the input event.
+ * The ending point is taken inside InputDispatcher, just after the input event
+ * is sent to the app.
*/
// Minimum value
optional float latency_min_micros = 1;
@@ -3062,9 +3071,9 @@ message PictureInPictureStateChanged {
* services/core/java/com/android/server/wm/Session.java
*/
message OverlayStateChanged {
- optional int32 uid = 1 [(is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
- optional string package_name = 2;
+ optional string package_name = 2 [(state_field_option).option = PRIMARY];
optional bool using_alert_window = 3;
@@ -3072,7 +3081,7 @@ message OverlayStateChanged {
ENTERED = 1;
EXITED = 2;
}
- optional State state = 4;
+ optional State state = 4 [(state_field_option).option = EXCLUSIVE];
}
/*
@@ -3965,7 +3974,7 @@ message ModemActivityInfo {
// rx time in ms at power level 5
optional uint64 controller_rx_time_millis = 9;
// product of current(mA), voltage(V) and time(ms)
- optional uint64 energy_used = 10;
+ optional uint64 energy_used = 10 [deprecated=true];
}
/**
@@ -4011,8 +4020,8 @@ message ProcessMemoryState {
optional int64 page_major_fault = 5;
// RSS
- // Value is read from /proc/PID/status. Or from memory.stat, field
- // total_rss if per-app memory cgroups are enabled.
+ // Value is read from memory.stat, field total_rss if per-app memory
+ // cgroups are enabled. Otherwise, value from /proc/pid/stat.
optional int64 rss_in_bytes = 6;
// CACHE
@@ -4022,67 +4031,52 @@ message ProcessMemoryState {
// SWAP
// Value is read from memory.stat, field total_swap if per-app memory
- // cgroups are enabled. Otherwise, VmSwap from /proc/PID/status.
+ // cgroups are enabled. Otherwise, 0.
optional int64 swap_in_bytes = 8;
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
+ // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1.
optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true];
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22. 0 if read from per-app memory cgroups.
- optional int64 start_time_nanos = 10;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int64 start_time_nanos = 10 [deprecated = true];
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 11;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true];
}
/*
- * Logs the memory stats for a native process (from procfs).
+ * Logs the memory high-water mark for a process.
+ *
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
+ * and for selected native processes.
*
- * Pulled from StatsCompanionService for selected native processes.
+ * Pulling this atom resets high-water mark counters for all processes.
*/
-message NativeProcessMemoryState {
+message ProcessMemoryHighWaterMark {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
// The process name.
- // Value read from /proc/PID/cmdline.
+ // Usually package name or process cmdline.
+ // Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
- // # of page-faults
- optional int64 page_fault = 3;
-
- // # of major page-faults
- optional int64 page_major_fault = 4;
-
- // RSS
- // Value read from /proc/PID/status.
- optional int64 rss_in_bytes = 5;
+ // Deprecated: use rss_high_water_mark_in_kilobytes instead. This field is
+ // computed by converting kilobytes to bytes.
+ optional int64 rss_high_water_mark_in_bytes = 3 [deprecated = true];
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
- optional int64 rss_high_watermark_in_bytes = 6 [deprecated = true];
-
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22.
- optional int64 start_time_nanos = 7;
-
- // SWAP
- // Value read from /proc/PID/status, field VmSwap.
- optional int64 swap_in_bytes = 8;
-
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 9;
+ // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
+ // /proc/PID/status.
+ optional int32 rss_high_water_mark_in_kilobytes = 4;
}
/*
- * Logs the memory high-water mark for a process.
+ * Logs the memory stats for a process.
*
- * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService)
* and for selected native processes.
- *
- * Pulling this atom resets high-water mark counters for all processes.
*/
-message ProcessMemoryHighWaterMark {
+message ProcessMemorySnapshot {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
@@ -4091,9 +4085,29 @@ message ProcessMemoryHighWaterMark {
// Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
- // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
- // /proc/PID/status.
- optional int64 rss_high_water_mark_in_bytes = 3;
+ // The pid of the process.
+ // Allows to disambiguate instances of the process.
+ optional int32 pid = 3;
+
+ // The current OOM score adjustment value.
+ // Read from ProcessRecord for managed processes.
+ // Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones.
+ optional int32 oom_score_adj = 4;
+
+ // The current RSS of the process.
+ // VmRSS from /proc/pid/status.
+ optional int32 rss_in_kilobytes = 5;
+
+ // The current anon RSS of the process.
+ // RssAnon from /proc/pid/status.
+ optional int32 anon_rss_in_kilobytes = 6;
+
+ // The current swap size of the process.
+ // VmSwap from /proc/pid/status.
+ optional int32 swap_in_kilobytes = 7;
+
+ // The sum of rss_in_kilobytes and swap_in_kilobytes.
+ optional int32 anon_rss_and_swap_in_kilobytes = 8;
}
/*
@@ -5937,7 +5951,8 @@ message BubbleUIChanged {
optional bool is_ongoing = 10;
// Whether the bubble is produced by an app running in foreground.
- optional bool is_foreground = 11;
+ // This is deprecated and the value should be ignored.
+ optional bool is_foreground = 11 [deprecated = true];
}
/**
@@ -7087,3 +7102,138 @@ message UpdateEngineSuccessfulUpdateReported {
// The number of reboot of the device during a successful update.
optional int32 reboot_count = 7;
}
+
+/**
+ * Global display pipeline metrics reported by SurfaceFlinger.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsGlobalInfo {
+ // Total number of frames presented during the tracing period
+ optional int64 total_frames = 1;
+ // Total number of frames missed
+ optional int64 missed_frames = 2;
+ // Total number of frames that fell back to client composition
+ optional int64 client_composition_frames = 3;
+ // Total time the display was turned on
+ optional int64 display_on_millis = 4;
+ // Total time that was spent performing animations.
+ // This is derived from the present-to-present layer histogram
+ optional int64 animation_millis = 5;
+}
+
+/**
+ * Per-layer display pipeline metrics reported by SurfaceFlinger.
+ * The number of layers uploaded will be restricted due to size limitations.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsLayerInfo {
+ // The layer for this set of metrics
+ // For now we can infer that the package name is included in the layer
+ // name.
+ optional string layer_name = 1;
+ // Total number of frames presented
+ optional int64 total_frames = 2;
+ // Total number of dropped frames while latching a buffer for this layer.
+ optional int64 dropped_frames = 3;
+ // Set of timings measured between successive presentation timestamps.
+ optional FrameTimingHistogram present_to_present = 4
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was actually presented to the
+ // display.
+ optional FrameTimingHistogram post_to_present = 5
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when a buffer is ready to be presented,
+ // until the buffer was actually presented to the display.
+ optional FrameTimingHistogram acquire_to_present = 6
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when a buffer was latched by
+ // SurfaceFlinger, until the buffer was presented to the display
+ optional FrameTimingHistogram latch_to_present = 7
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from the desired presentation to the actual
+ // presentation time
+ optional FrameTimingHistogram desired_to_present = 8
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was ready to be presented.
+ optional FrameTimingHistogram post_to_acquire = 9
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Histogram of frame counts bucketed by time in milliseconds.
+ * Because of size limitations, we hard-cap the number of buckets, with
+ * buckets for corresponding to larger milliseconds being less precise.
+ */
+message FrameTimingHistogram {
+ // Timings in milliseconds that describes a set of histogram buckets
+ repeated int32 time_millis_buckets = 1;
+ // Number of frames that match to each time_millis, i.e. the bucket
+ // contents
+ // It's required that len(time_millis) == len(frame_count)
+ repeated int64 frame_counts = 2;
+}
+
+/**
+ * Information about camera facing and API level usage.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java
+ */
+message CameraActionEvent {
+ // Camera session duration
+ optional int64 duration = 1;
+
+ // Camera API level used
+ optional int32 api_level = 2;
+
+ // Name of client package
+ optional string package_name = 3;
+
+ // Camera facing
+ enum Facing {
+ UNKNOWN = 0;
+ BACK = 1;
+ FRONT = 2;
+ EXTERNAL = 3;
+ }
+ optional Facing facing = 4;
+}
+
+/**
+ * Logs when a compatibility change is affecting an app.
+ *
+ * Logged from:
+ * frameworks/base/core/java/android/app/AppCompatCallbacks.java and
+ * frameworks/base/services/core/java/com/android/server/compat/PlatformCompat.java
+ */
+message AppCompatibilityChangeReported {
+ // The UID of the app being affected by the compatibilty change.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // The ID of the change affecting the app.
+ optional int64 change_id = 2;
+
+ enum State {
+ UNKNOWN_STATE = 0;
+ ENABLED = 1;
+ DISABLED = 2;
+ LOGGED = 3;
+ }
+
+ // The state of the change - if logged from gating whether it was enabled or disabled, or just
+ // logged otherwise.
+ optional State state = 3;
+
+ enum Source {
+ UNKNOWN_SOURCE = 0;
+ APP_PROCESS = 1;
+ SYSTEM_SERVER = 2;
+ }
+
+ // Where it was logged from.
+ optional Source source = 4;
+
+}
diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp
index 18c7178dd7d7..7f3eeddba831 100644
--- a/cmds/statsd/src/condition/StateTracker.cpp
+++ b/cmds/statsd/src/condition/StateConditionTracker.cpp
@@ -16,7 +16,7 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include "StateTracker.h"
+#include "StateConditionTracker.h"
#include "guardrail/StatsdStats.h"
namespace android {
@@ -27,7 +27,7 @@ using std::string;
using std::unordered_set;
using std::vector;
-StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index,
+StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
const unordered_map<int64_t, int>& trackerNameIndexMap,
const vector<Matcher> primaryKeys)
@@ -69,19 +69,19 @@ StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int in
mInitialized = true;
}
-StateTracker::~StateTracker() {
- VLOG("~StateTracker()");
+StateConditionTracker::~StateConditionTracker() {
+ VLOG("~StateConditionTracker()");
}
-bool StateTracker::init(const vector<Predicate>& allConditionConfig,
+bool StateConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack) {
return mInitialized;
}
-void StateTracker::dumpState() {
- VLOG("StateTracker %lld DUMP:", (long long)mConditionId);
+void StateConditionTracker::dumpState() {
+ VLOG("StateConditionTracker %lld DUMP:", (long long)mConditionId);
for (const auto& value : mSlicedState) {
VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str());
}
@@ -95,7 +95,7 @@ void StateTracker::dumpState() {
}
}
-bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
+bool StateConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
if (mSlicedState.find(newKey) != mSlicedState.end()) {
// if the condition is not sliced or the key is not new, we are good!
return false;
@@ -114,7 +114,7 @@ bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
return false;
}
-void StateTracker::evaluateCondition(const LogEvent& event,
+void StateConditionTracker::evaluateCondition(const LogEvent& event,
const vector<MatchingState>& eventMatcherValues,
const vector<sp<ConditionTracker>>& mAllConditions,
vector<ConditionState>& conditionCache,
@@ -135,7 +135,7 @@ void StateTracker::evaluateCondition(const LogEvent& event,
return;
}
- VLOG("StateTracker evaluate event %s", event.ToString().c_str());
+ VLOG("StateConditionTracker evaluate event %s", event.ToString().c_str());
// Primary key can exclusive fields must be simple fields. so there won't be more than
// one keys matched.
@@ -151,7 +151,7 @@ void StateTracker::evaluateCondition(const LogEvent& event,
}
hitGuardRail(primaryKey);
- VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
+ VLOG("StateConditionTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
auto it = mSlicedState.find(primaryKey);
if (it == mSlicedState.end()) {
@@ -176,7 +176,7 @@ void StateTracker::evaluateCondition(const LogEvent& event,
return;
}
-void StateTracker::isConditionMet(
+void StateConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
const bool isPartialLink,
vector<ConditionState>& conditionCache) const {
diff --git a/cmds/statsd/src/condition/StateTracker.h b/cmds/statsd/src/condition/StateConditionTracker.h
index 5ae4441713cd..0efe1fb3fcb2 100644
--- a/cmds/statsd/src/condition/StateTracker.h
+++ b/cmds/statsd/src/condition/StateConditionTracker.h
@@ -25,14 +25,14 @@ namespace android {
namespace os {
namespace statsd {
-class StateTracker : public virtual ConditionTracker {
+class StateConditionTracker : public virtual ConditionTracker {
public:
- StateTracker(const ConfigKey& key, const int64_t& id, const int index,
+ StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
const std::unordered_map<int64_t, int>& trackerNameIndexMap,
const vector<Matcher> primaryKeys);
- ~StateTracker();
+ ~StateConditionTracker();
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -46,8 +46,8 @@ public:
std::vector<bool>& changedCache) override;
/**
- * Note: dimensionFields will be ignored in StateTracker, because we demand metrics
- * must take the entire dimension fields from StateTracker. This is to make implementation
+ * Note: dimensionFields will be ignored in StateConditionTracker, because we demand metrics
+ * must take the entire dimension fields from StateConditionTracker. This is to make implementation
* simple and efficient.
*
* For example: wakelock duration by uid process states:
@@ -109,7 +109,7 @@ private:
// maps from [primary_key] to [primary_key, exclusive_state].
std::unordered_map<HashableDimensionKey, HashableDimensionKey> mSlicedState;
- FRIEND_TEST(StateTrackerTest, TestStateChange);
+ FRIEND_TEST(StateConditionTrackerTest, TestStateChange);
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index bbdb5405ca05..d38b87f046e0 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -92,9 +92,15 @@ static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
if (!event->write(info.appPackageName)) return false;
if (!event->write((int64_t)info.driverVersionCode)) return false;
- if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
- if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
- if (!event->write(int64VectorToProtoByteString(info.angleDriverLoadingTime))) return false;
+ if (!event->writeBytes(int64VectorToProtoByteString(info.glDriverLoadingTime))) {
+ return false;
+ }
+ if (!event->writeBytes(int64VectorToProtoByteString(info.vkDriverLoadingTime))) {
+ return false;
+ }
+ if (!event->writeBytes(int64VectorToProtoByteString(info.angleDriverLoadingTime))) {
+ return false;
+ }
if (!event->write(info.cpuVulkanInUse)) return false;
if (!event->write(info.falsePrerotation)) return false;
event->init();
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 475f18a9b0b8..43e33f59f612 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -17,12 +17,17 @@
#define DEBUG false
#include "Log.h"
+#include "StatsPullerManager.h"
+
#include <android/os/IStatsCompanionService.h>
#include <android/os/IStatsPullerCallback.h>
#include <cutils/log.h>
#include <math.h>
#include <stdint.h>
+
#include <algorithm>
+#include <iostream>
+
#include "../StatsService.h"
#include "../logd/LogEvent.h"
#include "../stats_log_util.h"
@@ -32,13 +37,11 @@
#include "ResourceHealthManagerPuller.h"
#include "StatsCallbackPuller.h"
#include "StatsCompanionServicePuller.h"
-#include "StatsPullerManager.h"
#include "SubsystemSleepStatePuller.h"
+#include "SurfaceflingerStatsPuller.h"
#include "TrainInfoPuller.h"
#include "statslog.h"
-#include <iostream>
-
using std::make_shared;
using std::map;
using std::shared_ptr;
@@ -142,17 +145,15 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {.additiveFields = {4, 5, 6, 7, 8, 9},
+ {.additiveFields = {4, 5, 6, 7, 8},
.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
- // native_process_memory_state
- {android::util::NATIVE_PROCESS_MEMORY_STATE,
- {.additiveFields = {3, 4, 5, 6, 8},
- .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
// process_memory_high_water_mark
{android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
- {.additiveFields = {3},
- .puller =
+ {.puller =
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
+ // process_memory_snapshot
+ {android::util::PROCESS_MEMORY_SNAPSHOT,
+ {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}},
// system_ion_heap_size
{android::util::SYSTEM_ION_HEAP_SIZE,
{.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
@@ -266,6 +267,10 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// App ops
{android::util::APP_OPS,
{.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}},
+ // SurfaceflingerStatsGlobalInfo
+ {android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ {.puller =
+ new SurfaceflingerStatsPuller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
new file mode 100644
index 000000000000..23b2236f35f2
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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 "SurfaceflingerStatsPuller.h"
+
+#include <cutils/compiler.h>
+
+#include <numeric>
+
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SurfaceflingerStatsPuller::SurfaceflingerStatsPuller(const int tagId) : StatsPuller(tagId) {
+}
+
+bool SurfaceflingerStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
+ switch (mTagId) {
+ case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
+ return pullGlobalInfo(data);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int64_t getTotalTime(
+ const google::protobuf::RepeatedPtrField<surfaceflinger::SFTimeStatsHistogramBucketProto>&
+ buckets) {
+ int64_t total = 0;
+ for (const auto& bucket : buckets) {
+ if (bucket.time_millis() == 1000) {
+ continue;
+ }
+
+ total += bucket.time_millis() * bucket.frame_count();
+ }
+
+ return total;
+}
+
+bool SurfaceflingerStatsPuller::pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data) {
+ std::string protoBytes;
+ if (CC_UNLIKELY(mStatsProvider)) {
+ protoBytes = mStatsProvider();
+ } else {
+ std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("dumpsys SurfaceFlinger --timestats -dump --proto", "r"), pclose);
+ if (!pipe.get()) {
+ return false;
+ }
+ char buf[1024];
+ size_t bytesRead = 0;
+ do {
+ bytesRead = fread(buf, 1, sizeof(buf), pipe.get());
+ protoBytes.append(buf, bytesRead);
+ } while (bytesRead > 0);
+ }
+ surfaceflinger::SFTimeStatsGlobalProto proto;
+ proto.ParseFromString(protoBytes);
+
+ int64_t totalTime = getTotalTime(proto.present_to_present());
+
+ data->clear();
+ data->reserve(1);
+ std::shared_ptr<LogEvent> event =
+ make_shared<LogEvent>(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, getWallClockNs(),
+ getElapsedRealtimeNs());
+ if (!event->write(proto.total_frames())) return false;
+ if (!event->write(proto.missed_frames())) return false;
+ if (!event->write(proto.client_composition_frames())) return false;
+ if (!event->write(proto.display_on_time())) return false;
+ if (!event->write(totalTime)) return false;
+ event->init();
+ data->emplace_back(event);
+
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.h b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
new file mode 100644
index 000000000000..ed7153edf797
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <timestatsproto/TimeStatsProtoHeader.h>
+
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Pull metrics from Surfaceflinger
+ */
+class SurfaceflingerStatsPuller : public StatsPuller {
+public:
+ explicit SurfaceflingerStatsPuller(const int tagId);
+
+ // StatsPuller interface
+ bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
+
+protected:
+ // Test-only, for injecting fake data
+ using StatsProvider = std::function<std::string()>;
+ StatsProvider mStatsProvider;
+
+private:
+ bool pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 0ade53118d77..fd19c9d61f87 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -332,6 +332,13 @@ bool LogEvent::write(float value) {
return false;
}
+bool LogEvent::writeBytes(const string& value) {
+ if (mContext) {
+ return android_log_write_char_array(mContext, value.c_str(), value.length()) >= 0;
+ }
+ return false;
+}
+
bool LogEvent::writeKeyValuePairs(int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 531ce299beef..f1f45a2d3bc7 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -21,9 +21,9 @@
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/StatsLogEventWrapper.h>
#include <android/util/ProtoOutputStream.h>
-#include <log/log_event_list.h>
#include <log/log_read.h>
#include <private/android_logger.h>
+#include <stats_event_list.h>
#include <utils/Errors.h>
#include <string>
@@ -157,6 +157,7 @@ public:
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
+ bool writeBytes(const std::string& value);
bool writeKeyValuePairs(int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 68082c2dc4d2..7d446a9a1ed6 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -53,6 +53,8 @@ void sigHandler(int sig) {
if (gStatsService != nullptr) {
gStatsService->Terminate();
}
+ ALOGW("statsd terminated on receiving signal %d.", sig);
+ exit(1);
}
void registerSigHandler()
@@ -78,7 +80,7 @@ int main(int /*argc*/, char** /*argv*/) {
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
- ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
+ ::android::hardware::configureRpcThreadpool(4 /*threads*/, false /*willJoin*/);
std::shared_ptr<LogEventQueue> eventQueue =
std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 10ac4a182f87..476fae37899d 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -358,9 +358,10 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher,
const LogEvent& event) {
- if (simpleMatcher.field_value_matcher_size() <= 0) {
- return event.GetTagId() == simpleMatcher.atom_id();
+ if (event.GetTagId() != simpleMatcher.atom_id()) {
+ return false;
}
+
for (const auto& matcher : simpleMatcher.field_value_matcher()) {
if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) {
return false;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 94f833b20814..fdbdc83fb66e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -83,9 +83,9 @@ public:
mCurrentBucketStartTimeNs(timeBaseNs),
mCurrentBucketNum(0),
mCondition(initialCondition(conditionIndex)),
+ mConditionTrackerIndex(conditionIndex),
mConditionSliced(false),
mWizard(wizard),
- mConditionTrackerIndex(conditionIndex),
mContainANYPositionInDimensionsInWhat(false),
mSliceByPositionALL(false),
mHasLinksToAllConditionDimensionsInTracker(false),
@@ -167,11 +167,6 @@ public:
return clearPastBucketsLocked(dumpTimeNs);
}
- void dumpStates(FILE* out, bool verbose) const {
- std::lock_guard<std::mutex> lock(mMutex);
- dumpStatesLocked(out, verbose);
- }
-
// Returns the memory in bytes currently used to store this metric's data. Does not change
// state.
size_t byteSize() const {
@@ -179,34 +174,9 @@ public:
return byteSizeLocked();
}
- /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
- virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
- const sp<AlarmMonitor>& anomalyAlarmMonitor) {
- std::lock_guard<std::mutex> lock(mMutex);
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
- if (anomalyTracker != nullptr) {
- mAnomalyTrackers.push_back(anomalyTracker);
- }
- return anomalyTracker;
- }
-
- int64_t getBuckeSizeInNs() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return mBucketSizeNs;
- }
-
- // Only needed for unit-testing to override guardrail.
- void setBucketSize(int64_t bucketSize) {
- mBucketSizeNs = bucketSize;
- }
-
- inline const int64_t& getMetricId() const {
- return mMetricId;
- }
-
- void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
+ void dumpStates(FILE* out, bool verbose) const {
std::lock_guard<std::mutex> lock(mMutex);
- loadActiveMetricLocked(activeMetric, currentTimeNs);
+ dumpStatesLocked(out, verbose);
}
// Let MetricProducer drop in-memory data to save memory.
@@ -218,9 +188,14 @@ public:
dropDataLocked(dropTimeNs);
}
- // For test only.
- inline int64_t getCurrentBucketNum() const {
- return mCurrentBucketNum;
+ void prepareFirstBucket() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ prepareFirstBucketLocked();
+ }
+
+ void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ loadActiveMetricLocked(activeMetric, currentTimeNs);
}
void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
@@ -238,44 +213,41 @@ public:
return isActiveLocked();
}
+ void flushIfExpire(int64_t elapsedTimestampNs);
+
void addActivation(int activationTrackerIndex, const ActivationType& activationType,
int64_t ttl_seconds, int deactivationTrackerIndex = -1);
- void prepareFirstBucket() {
- std::lock_guard<std::mutex> lock(mMutex);
- prepareFirstBucketLocked();
- }
-
- void flushIfExpire(int64_t elapsedTimestampNs);
-
void writeActiveMetricToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-protected:
- virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
- virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
- const int64_t eventTime) = 0;
- virtual void onDumpReportLocked(const int64_t dumpTimeNs,
- const bool include_current_partial_bucket,
- const bool erase_data,
- const DumpLatency dumpLatency,
- std::set<string> *str_set,
- android::util::ProtoOutputStream* protoOutput) = 0;
- virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
- virtual size_t byteSizeLocked() const = 0;
- virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
- bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
-
- void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
- void cancelEventActivationLocked(int deactivationTrackerIndex);
+ // Start: getters/setters
+ inline const int64_t& getMetricId() const {
+ return mMetricId;
+ }
- inline bool isActiveLocked() const {
- return mIsActive;
+ // For test only.
+ inline int64_t getCurrentBucketNum() const {
+ return mCurrentBucketNum;
}
- void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
+ int64_t getBucketSizeInNs() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mBucketSizeNs;
+ }
- virtual void prepareFirstBucketLocked() {};
+ /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
+ virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
+ if (anomalyTracker != nullptr) {
+ mAnomalyTrackers.push_back(anomalyTracker);
+ }
+ return anomalyTracker;
+ }
+ // End: getters/setters
+protected:
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
@@ -283,14 +255,6 @@ protected:
virtual void flushIfNeededLocked(const int64_t& eventTime){};
/**
- * Flushes all the data including the current partial bucket.
- */
- virtual void flushLocked(const int64_t& eventTimeNs) {
- flushIfNeededLocked(eventTimeNs);
- flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
- };
-
- /**
* For metrics that aggregate (ie, every metric producer except for EventMetricProducer),
* we need to be able to flush the current buckets on demand (ie, end the current bucket and
* start new bucket). If this function is called when eventTimeNs is greater than the current
@@ -303,12 +267,66 @@ protected:
virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) {};
+ /**
+ * Flushes all the data including the current partial bucket.
+ */
+ virtual void flushLocked(const int64_t& eventTimeNs) {
+ flushIfNeededLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
+ };
+
+ /*
+ * Individual metrics can implement their own business logic here. All pre-processing is done.
+ *
+ * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
+ * DurationMetric, because it has start/stop/stop_all 3 matchers.
+ * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
+ * dimensions, it will be DEFAULT_DIMENSION_KEY
+ * [conditionKey]: the keys of conditions which should be used to query the condition for this
+ * target event (from MetricConditionLink). This is passed to individual metrics
+ * because DurationMetric needs it to be cached.
+ * [condition]: whether condition is met. If condition is sliced, this is the result coming from
+ * query with ConditionWizard; If condition is not sliced, this is the
+ * nonSlicedCondition.
+ * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
+ */
+ virtual void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKey, bool condition,
+ const LogEvent& event) = 0;
+
+ // Consume the parsed stats log entry that already matched the "what" of the metric.
+ virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
+ virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
+ virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
+ const int64_t eventTime) = 0;
+ virtual void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
+ const bool erase_data,
+ const DumpLatency dumpLatency,
+ std::set<string> *str_set,
+ android::util::ProtoOutputStream* protoOutput) = 0;
+ virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
+ virtual size_t byteSizeLocked() const = 0;
+ virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
+ virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
+ virtual void prepareFirstBucketLocked() {};
+ void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
+ void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
+ void cancelEventActivationLocked(int deactivationTrackerIndex);
+
+ bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
+
virtual void onActiveStateChangedLocked(const int64_t& eventTimeNs) {
if (!mIsActive) {
flushLocked(eventTimeNs);
}
}
+ inline bool isActiveLocked() const {
+ return mIsActive;
+ }
+
// Convenience to compute the current bucket's end time, which is always aligned with the
// start time of the metric.
int64_t getCurrentBucketEndTimeNs() const {
@@ -319,8 +337,6 @@ protected:
return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
}
- virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
-
const int64_t mMetricId;
const ConfigKey mConfigKey;
@@ -341,17 +357,18 @@ protected:
ConditionState mCondition;
+ int mConditionTrackerIndex;
+
bool mConditionSliced;
sp<ConditionWizard> mWizard;
- int mConditionTrackerIndex;
-
- vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
-
bool mContainANYPositionInDimensionsInWhat;
+
bool mSliceByPositionALL;
+ vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
+
// True iff the metric to condition links cover all dimension fields in the condition tracker.
// This field is always false for combinational condition trackers.
bool mHasLinksToAllConditionDimensionsInTracker;
@@ -360,29 +377,6 @@ protected:
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
- /*
- * Individual metrics can implement their own business logic here. All pre-processing is done.
- *
- * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
- * DurationMetric, because it has start/stop/stop_all 3 matchers.
- * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
- * dimensions, it will be DEFAULT_DIMENSION_KEY
- * [conditionKey]: the keys of conditions which should be used to query the condition for this
- * target event (from MetricConditionLink). This is passed to individual metrics
- * because DurationMetric needs it to be cached.
- * [condition]: whether condition is met. If condition is sliced, this is the result coming from
- * query with ConditionWizard; If condition is not sliced, this is the
- * nonSlicedCondition.
- * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
- */
- virtual void onMatchedLogEventInternalLocked(
- const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) = 0;
-
- // Consume the parsed stats log entry that already matched the "what" of the metric.
- virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
-
mutable std::mutex mMutex;
struct Activation {
@@ -397,6 +391,7 @@ protected:
ActivationState state;
const ActivationType activationType;
};
+
// When the metric producer has multiple activations, these activations are ORed to determine
// whether the metric producer is ready to generate metrics.
std::unordered_map<int, std::shared_ptr<Activation>> mEventActivationMap;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index dd32c08faba3..40484f4fb86b 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -21,7 +21,7 @@
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
-#include "../condition/StateTracker.h"
+#include "../condition/StateConditionTracker.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
@@ -35,6 +35,8 @@
#include "stats_util.h"
#include "statslog.h"
+#include <inttypes.h>
+
using std::set;
using std::string;
using std::unordered_map;
@@ -182,13 +184,13 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
}
/**
- * A StateTracker is built from a SimplePredicate which has only "start", and no "stop"
+ * A StateConditionTracker is built from a SimplePredicate which has only "start", and no "stop"
* or "stop_all". The start must be an atom matcher that matches a state atom. It must
* have dimension, the dimension must be the state atom's primary fields plus exclusive state
- * field. For example, the StateTracker is used in tracking UidProcessState and ScreenState.
+ * field. For example, the StateConditionTracker is used in tracking UidProcessState and ScreenState.
*
*/
-bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
+bool isStateConditionTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
// 1. must not have "stop". must have "dimension"
if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
@@ -240,8 +242,8 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
switch (condition.contents_case()) {
case Predicate::ContentsCase::kSimplePredicate: {
vector<Matcher> primaryKeys;
- if (isStateTracker(condition.simple_predicate(), &primaryKeys)) {
- allConditionTrackers.push_back(new StateTracker(key, condition.id(), index,
+ if (isStateConditionTracker(condition.simple_predicate(), &primaryKeys)) {
+ allConditionTrackers.push_back(new StateConditionTracker(key, condition.id(), index,
condition.simple_predicate(),
logTrackerMap, primaryKeys));
} else {
@@ -593,7 +595,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
for (int i = 0; i < config.no_report_metric_size(); ++i) {
const auto no_report_metric = config.no_report_metric(i);
if (metricMap.find(no_report_metric) == metricMap.end()) {
- ALOGW("no_report_metric %lld not exist", no_report_metric);
+ ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
return false;
}
noReportMetricIds.insert(no_report_metric);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 028231ff908c..3704969039c4 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -113,7 +113,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds);
-bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
+bool isStateConditionTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
new file mode 100644
index 000000000000..a31690a102ed
--- /dev/null
+++ b/cmds/statsd/src/state/StateListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <utils/RefBase.h>
+
+#include "HashableDimensionKey.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateListener : public virtual RefBase {
+public:
+ StateListener(){};
+
+ virtual ~StateListener(){};
+
+ /**
+ * Interface for handling a state change.
+ *
+ * The old and new state values map to the original state values.
+ * StateTrackers only track the original state values and are unaware
+ * of higher-level state groups. MetricProducers hold information on
+ * state groups and are responsible for mapping original state values to
+ * the correct state group.
+ *
+ * [atomId]: The id of the state atom
+ * [primaryKey]: The primary field values of the state atom
+ * [oldState]: Previous state value before state change
+ * [newState]: Current state value after state change
+ */
+ virtual void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
+ int newState) = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
new file mode 100644
index 000000000000..a3059c5b52ac
--- /dev/null
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include "StateManager.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StateManager& StateManager::getInstance() {
+ static StateManager sStateManager;
+ return sStateManager;
+}
+
+void StateManager::onLogEvent(const LogEvent& event) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) {
+ mStateTrackers[event.GetTagId()]->onLogEvent(event);
+ }
+}
+
+bool StateManager::registerListener(int stateAtomId, wp<StateListener> listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ // Check if state tracker already exists
+ if (mStateTrackers.find(stateAtomId) == mStateTrackers.end()) {
+ // Create a new state tracker iff atom is a state atom
+ auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(stateAtomId);
+ if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
+ mStateTrackers[stateAtomId] = new StateTracker(stateAtomId, it->second);
+ } else {
+ ALOGE("StateManager cannot register listener, Atom %d is not a state atom",
+ stateAtomId);
+ return false;
+ }
+ }
+ mStateTrackers[stateAtomId]->registerListener(listener);
+ return true;
+}
+
+void StateManager::unregisterListener(int stateAtomId, wp<StateListener> listener) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ // Hold the sp<> until the lock is released so that ~StateTracker() is
+ // not called while the lock is held.
+ sp<StateTracker> toRemove;
+
+ // Unregister listener from correct StateTracker
+ auto it = mStateTrackers.find(stateAtomId);
+ if (it != mStateTrackers.end()) {
+ it->second->unregisterListener(listener);
+
+ // Remove the StateTracker if it has no listeners
+ if (it->second->getListenersCount() == 0) {
+ toRemove = it->second;
+ mStateTrackers.erase(it);
+ }
+ } else {
+ ALOGE("StateManager cannot unregister listener, StateTracker for atom %d does not exist",
+ stateAtomId);
+ }
+ lock.unlock();
+}
+
+int StateManager::getState(int stateAtomId, const HashableDimensionKey& key) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(stateAtomId) != mStateTrackers.end()) {
+ return mStateTrackers[stateAtomId]->getState(key);
+ }
+
+ return StateTracker::kStateUnknown;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
new file mode 100644
index 000000000000..ce60f1482be7
--- /dev/null
+++ b/cmds/statsd/src/state/StateManager.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+//#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include "HashableDimensionKey.h"
+
+#include "state/StateListener.h"
+#include "state/StateTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateManager : public virtual RefBase {
+public:
+ StateManager(){};
+
+ ~StateManager(){};
+
+ // Returns a pointer to the single, shared StateManager object.
+ static StateManager& getInstance();
+
+ // Notifies the correct StateTracker of an event.
+ void onLogEvent(const LogEvent& event);
+
+ // Returns true if stateAtomId is the id of a state atom and notifies the
+ // correct StateTracker to register the listener. If the correct
+ // StateTracker does not exist, a new StateTracker is created.
+ bool registerListener(int stateAtomId, wp<StateListener> listener);
+
+ // Notifies the correct StateTracker to unregister a listener
+ // and removes the tracker if it no longer has any listeners.
+ void unregisterListener(int stateAtomId, wp<StateListener> listener);
+
+ // Queries the correct StateTracker for the state that is mapped to the given
+ // query key.
+ // If the StateTracker doesn't exist, returns StateTracker::kStateUnknown.
+ int getState(int stateAtomId, const HashableDimensionKey& queryKey);
+
+ inline int getStateTrackersCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mStateTrackers.size();
+ }
+
+ inline int getListenersCount(int stateAtomId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(stateAtomId) != mStateTrackers.end()) {
+ return mStateTrackers[stateAtomId]->getListenersCount();
+ }
+ return -1;
+ }
+
+private:
+ mutable std::mutex mMutex;
+
+ // Maps state atom ids to StateTrackers
+ std::unordered_map<int, sp<StateTracker>> mStateTrackers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
new file mode 100644
index 000000000000..5a91950b9f8b
--- /dev/null
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "stats_util.h"
+
+#include "StateTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StateTracker::StateTracker(const int atomId,
+ const util::StateAtomFieldOptions& stateAtomInfo)
+ : mAtomId(atomId),
+ mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
+ // create matcher for each primary field
+ // TODO(tsaichristine): handle when primary field is first uid in chain
+ for (const auto& primary : stateAtomInfo.primaryFields) {
+ Matcher matcher = getSimpleMatcher(atomId, primary);
+ mPrimaryFields.push_back(matcher);
+ }
+
+ // TODO(tsaichristine): set default state, reset state, and nesting
+}
+
+void StateTracker::onLogEvent(const LogEvent& event) {
+ // parse event for primary field values i.e. primary key
+ HashableDimensionKey primaryKey;
+ if (mPrimaryFields.size() > 0) {
+ if (!filterValues(mPrimaryFields, event.getValues(), &primaryKey) ||
+ primaryKey.getValues().size() != mPrimaryFields.size()) {
+ ALOGE("StateTracker error extracting primary key from log event.");
+ handleReset();
+ return;
+ }
+ } else {
+ // atom has no primary fields
+ primaryKey = DEFAULT_DIMENSION_KEY;
+ }
+
+ // parse event for state value
+ Value state;
+ int32_t stateValue;
+ if (!filterValues(mStateField, event.getValues(), &state) || state.getType() != INT) {
+ ALOGE("StateTracker error extracting state from log event. Type: %d", state.getType());
+ handlePartialReset(primaryKey);
+ return;
+ }
+ stateValue = state.int_value;
+
+ if (stateValue == mResetState) {
+ VLOG("StateTracker Reset state: %s", state.toString().c_str());
+ handleReset();
+ }
+
+ // track and update state
+ int32_t oldState = 0;
+ int32_t newState = 0;
+ updateState(primaryKey, stateValue, &oldState, &newState);
+
+ // notify all listeners if state has changed
+ if (oldState != newState) {
+ VLOG("StateTracker updated state");
+ for (auto listener : mListeners) {
+ auto sListener = listener.promote(); // safe access to wp<>
+ if (sListener != nullptr) {
+ sListener->onStateChanged(mAtomId, primaryKey, oldState, newState);
+ }
+ }
+ } else {
+ VLOG("StateTracker NO updated state");
+ }
+}
+
+void StateTracker::registerListener(wp<StateListener> listener) {
+ mListeners.insert(listener);
+}
+
+void StateTracker::unregisterListener(wp<StateListener> listener) {
+ mListeners.erase(listener);
+}
+
+int StateTracker::getState(const HashableDimensionKey& queryKey) const {
+ if (queryKey.getValues().size() == mPrimaryFields.size()) {
+ auto it = mStateMap.find(queryKey);
+ if (it != mStateMap.end()) {
+ return it->second.state;
+ }
+ } else if (queryKey.getValues().size() > mPrimaryFields.size()) {
+ ALOGE("StateTracker query key size > primary key size is illegal");
+ } else {
+ ALOGE("StateTracker query key size < primary key size is not supported");
+ }
+ return mDefaultState;
+}
+
+void StateTracker::handleReset() {
+ VLOG("StateTracker handle reset");
+ for (const auto pair : mStateMap) {
+ for (auto l : mListeners) {
+ auto sl = l.promote();
+ if (sl != nullptr) {
+ sl->onStateChanged(mAtomId, pair.first, pair.second.state, mDefaultState);
+ }
+ }
+ }
+ mStateMap.clear();
+}
+
+void StateTracker::handlePartialReset(const HashableDimensionKey& primaryKey) {
+ VLOG("StateTracker handle partial reset");
+ if (mStateMap.find(primaryKey) != mStateMap.end()) {
+ mStateMap.erase(primaryKey);
+ }
+}
+
+void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
+ int32_t* oldState, int32_t* newState) {
+ // get old state (either current state in map or default state)
+ auto it = mStateMap.find(primaryKey);
+ if (it != mStateMap.end()) {
+ *oldState = it->second.state;
+ } else {
+ *oldState = mDefaultState;
+ }
+
+ // update state map
+ if (eventState == mDefaultState) {
+ // remove (key, state) pair if state returns to default state
+ VLOG("\t StateTracker changed to default state")
+ mStateMap.erase(primaryKey);
+ } else {
+ mStateMap[primaryKey].state = eventState;
+ mStateMap[primaryKey].count = 1;
+ }
+ *newState = eventState;
+
+ // TODO(tsaichristine): support atoms with nested counting
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
new file mode 100644
index 000000000000..f22706c8418d
--- /dev/null
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <statslog.h>
+#include <utils/RefBase.h>
+#include "HashableDimensionKey.h"
+#include "logd/LogEvent.h"
+
+#include "state/StateListener.h"
+
+#include <unordered_map>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateTracker : public virtual RefBase {
+public:
+ StateTracker(const int atomId, const util::StateAtomFieldOptions& stateAtomInfo);
+
+ virtual ~StateTracker(){};
+
+ // Updates state map and notifies all listeners if a state change occurs.
+ // Checks if a state change has occurred by getting the state value from
+ // the log event and comparing the old and new states.
+ void onLogEvent(const LogEvent& event);
+
+ // Adds new listeners to set of StateListeners. If a listener is already
+ // registered, it is ignored.
+ void registerListener(wp<StateListener> listener);
+
+ void unregisterListener(wp<StateListener> listener);
+
+ // Returns the state value mapped to the given query key.
+ // If the key isn't mapped to a state or the key size doesn't match the
+ // primary key size, the default state is returned.
+ int getState(const HashableDimensionKey& queryKey) const;
+
+ inline int getListenersCount() const {
+ return mListeners.size();
+ }
+
+ const static int kStateUnknown = -1;
+
+private:
+ struct StateValueInfo {
+ int32_t state; // state value
+ int count; // nested count (only used for binary states)
+ };
+
+ const int32_t mAtomId; // id of the state atom being tracked
+
+ Matcher mStateField; // matches the atom's exclusive state field
+
+ std::vector<Matcher> mPrimaryFields; // matches the atom's primary fields
+
+ int32_t mDefaultState = kStateUnknown;
+
+ int32_t mResetState;
+
+ // Maps primary key to state value info
+ std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
+
+ // Set of all StateListeners (objects listening for state changes)
+ std::set<wp<StateListener>> mListeners;
+
+ // Reset all state values in map to default state
+ void handleReset();
+
+ // Reset only the state value mapped to primary key to default state
+ void handlePartialReset(const HashableDimensionKey& primaryKey);
+
+ // Update the StateMap based on the received state value.
+ // Store the old and new states.
+ void updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
+ int32_t* oldState, int32_t* newState);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index d9c04f248af0..e45e24fe49d4 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -41,6 +41,15 @@ message DimensionsValueTuple {
repeated DimensionsValue dimensions_value = 1;
}
+message StateValue {
+ optional int32 atom_id = 1;
+
+ oneof contents {
+ int64 group_id = 2;
+ int32 value = 3;
+ }
+}
+
message EventMetricData {
optional int64 elapsed_timestamp_nanos = 1;
@@ -66,12 +75,14 @@ message CountBucketInfo {
message CountMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
+ repeated StateValue slice_by_state = 6;
repeated CountBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
+
repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1b7f39806608..c107397b0273 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -150,6 +150,24 @@ message Predicate {
}
}
+message StateMap {
+ message StateGroup {
+ optional int64 group_id = 1;
+
+ repeated int32 value = 2;
+ }
+
+ repeated StateGroup group = 1;
+}
+
+message State {
+ optional int64 id = 1;
+
+ optional int32 atom_id = 2;
+
+ optional StateMap map = 3;
+}
+
message MetricConditionLink {
optional int64 condition = 1;
@@ -158,6 +176,14 @@ message MetricConditionLink {
optional FieldMatcher fields_in_condition = 3;
}
+message MetricStateLink {
+ optional int64 state = 1;
+
+ optional FieldMatcher fields_in_what = 2;
+
+ optional FieldMatcher fields_in_state = 3;
+}
+
message FieldFilter {
optional bool include_all = 1 [default = false];
optional FieldMatcher fields = 2;
@@ -182,11 +208,15 @@ message CountMetric {
optional FieldMatcher dimensions_in_what = 4;
- optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
+ repeated int64 slice_by_state = 8;
optional TimeUnit bucket = 5;
repeated MetricConditionLink links = 6;
+
+ repeated MetricStateLink state_link = 9;
+
+ optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
}
message DurationMetric {
@@ -438,6 +468,8 @@ message StatsdConfig {
optional bool persist_locally = 20 [default = false];
+ repeated State state = 21;
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 70f0f6f75a59..441d3c896467 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -330,6 +330,7 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) {
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
// Tag found in kAtomsWithUidField and has matching uid
+ simpleMatcher->set_atom_id(TAG_ID_2);
EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
// Tag found in kAtomsWithUidField but has non-matching uid
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 504ee22f72e4..0743480bf4ee 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -582,7 +582,7 @@ TEST(LogEventTest, TestBinaryFieldAtom) {
event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
- event1.write(extension_str);
+ event1.writeBytes(extension_str);
event1.init();
ProtoOutputStream proto;
@@ -621,7 +621,7 @@ TEST(LogEventTest, TestBinaryFieldAtom_empty) {
event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
- event1.write(extension_str);
+ event1.writeBytes(extension_str);
event1.init();
ProtoOutputStream proto;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index fe25a257aa67..460b9e0995c8 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -1199,87 +1199,66 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
ConfigKey cfgKey1(uid, 12341);
long timeBase1 = 1;
- sp<StatsLogProcessor> processor =
+ sp<StatsLogProcessor> processor1 =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor->mMetricsManagers.size());
- auto it = processor->mMetricsManagers.find(cfgKey1);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ EXPECT_EQ(1, processor1->mMetricsManagers.size());
+ auto it = processor1->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor1->mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
- auto metricIt = metricsManager1->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
- auto& metricProducer1 = *metricIt;
- EXPECT_FALSE(metricProducer1->isActive());
-
- metricIt = metricsManager1->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
- auto& metricProducer2 = *metricIt;
- EXPECT_TRUE(metricProducer2->isActive());
-
- int i = 0;
- for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
- if (metricsManager1->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
- EXPECT_EQ(0, activation1->start_ns);
- EXPECT_EQ(kNotActive, activation1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
-
- i = 0;
- for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
- if (metricsManager1->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
- EXPECT_EQ(0, activation2->start_ns);
- EXPECT_EQ(kNotActive, activation2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
+ EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
+
+ auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer1_2->isActive());
+
+ EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
+
+ const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
// }}}------------------------------------------------------------------------------
// Trigger Activation 1 for Metric 1
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
- processor->OnLogEvent(event.get());
+ processor1->OnLogEvent(event.get());
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_FALSE(metricProducer1->isActive());
- EXPECT_EQ(0, activation1->start_ns);
- EXPECT_EQ(kActiveOnBoot, activation1->state);
- EXPECT_EQ(0, activation2->start_ns);
- EXPECT_EQ(kNotActive, activation2->state);
+ EXPECT_FALSE(metricProducer1_1->isActive());
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
- EXPECT_TRUE(metricProducer2->isActive());
+ EXPECT_TRUE(metricProducer1_2->isActive());
// }}}-----------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
- processor->SaveActiveConfigsToDisk(shutDownTime);
- EXPECT_FALSE(metricProducer1->isActive());
- int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+ processor1->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1_1->isActive());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
@@ -1293,55 +1272,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
EXPECT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
- auto& metricsManager1001 = it->second;
- EXPECT_TRUE(metricsManager1001->isActive());
-
- metricIt = metricsManager1001->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
- auto& metricProducer1001 = *metricIt;
- EXPECT_FALSE(metricProducer1001->isActive());
-
- metricIt = metricsManager1001->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
- auto& metricProducer1002 = *metricIt;
- EXPECT_TRUE(metricProducer1002->isActive());
-
- i = 0;
- for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
- if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
- EXPECT_EQ(0, activation1001_1->start_ns);
- EXPECT_EQ(kNotActive, activation1001_1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001_1->activationType);
-
- i = 0;
- for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
- if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
+ auto& metricsManager2 = it->second;
+ EXPECT_TRUE(metricsManager2->isActive());
- const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
- EXPECT_EQ(0, activation1001_2->start_ns);
- EXPECT_EQ(kNotActive, activation1001_2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1001_2->activationType);
+ EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer2_1->isActive());
+
+ auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer2_2->isActive());
+
+ EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
+ EXPECT_EQ(0, activation2_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
+
+ const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
// }}}-----------------------------------------------------------------------------------
// Load saved state from disk.
@@ -1350,13 +1308,14 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active; Activation 1 is active, Activation 2 is not active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
- EXPECT_EQ(kActive, activation1001_1->state);
- EXPECT_EQ(0, activation1001_2->start_ns);
- EXPECT_EQ(kNotActive, activation1001_2->state);
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
- EXPECT_TRUE(metricProducer1002->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
// }}}--------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1.
@@ -1369,23 +1328,23 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active; Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
- EXPECT_EQ(kActive, activation1001_1->state);
- EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation1001_2->start_ns);
- EXPECT_EQ(kActive, activation1001_2->state);
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
+ EXPECT_EQ(kActive, activation2_1_2->state);
- EXPECT_TRUE(metricProducer1002->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
// }}}---------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
processor2->SaveActiveConfigsToDisk(shutDownTime);
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_TRUE(metricProducer1002->isActive());
- ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
- int64_t ttl2 = screenOnEvent->GetElapsedTimestampNs() +
- metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
+ ttl1 -= shutDownTime - timeBase2;
+ int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC
+ - (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
@@ -1399,55 +1358,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
EXPECT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
- auto& metricsManagerTimeBase3 = it->second;
- EXPECT_TRUE(metricsManagerTimeBase3->isActive());
-
- metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
- for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
- auto& metricProducerTimeBase3_1 = *metricIt;
- EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
-
- metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
- for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
- auto& metricProducerTimeBase3_2 = *metricIt;
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-
- i = 0;
- for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
- if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
- EXPECT_EQ(0, activationTimeBase3_1->start_ns);
- EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activationTimeBase3_1->activationType);
-
- i = 0;
- for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
- if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
+ auto& metricsManager3 = it->second;
+ EXPECT_TRUE(metricsManager3->isActive());
- const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
- EXPECT_EQ(0, activationTimeBase3_2->start_ns);
- EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activationTimeBase3_2->activationType);
+ EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer3_1->isActive());
+
+ auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer3_2->isActive());
+
+ EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
+ EXPECT_EQ(0, activation3_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
+
+ const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
+ EXPECT_EQ(0, activation3_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
// }}}----------------------------------------------------------------------------------
// Load saved state from disk.
@@ -1456,13 +1394,13 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active: Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
- EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_1->state);
- EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_2->state);
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
+ EXPECT_EQ(kActive, activation3_1_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ EXPECT_TRUE(metricProducer3_2->isActive());
// }}}-------------------------------------------------------------------------------
@@ -1473,15 +1411,16 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
);
processor3->OnLogEvent(screenOnEvent.get());
- // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
+ // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
+ // Activation 2 is set to active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
- EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
- EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activationTimeBase3_2->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_2->state);
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ EXPECT_TRUE(metricProducer3_2->isActive());
// }}}---------------------------------------------------------------------------
}
@@ -1713,6 +1652,11 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
EXPECT_EQ(kActive, activation1004->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
// }}}------------------------------------------------------------------------------
+
+ // Clear the data stored on disk as a result of the system server death.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer);
}
#else
diff --git a/cmds/statsd/tests/condition/StateTracker_test.cpp b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp
index 9a66254afce0..fbf6efdcf966 100644
--- a/cmds/statsd/tests/condition/StateTracker_test.cpp
+++ b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "src/condition/StateTracker.h"
+#include "src/condition/StateConditionTracker.h"
#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
@@ -50,7 +50,7 @@ void makeUidProcStateEvent(int32_t uid, int32_t state, LogEvent* event) {
event->init();
}
-TEST(StateTrackerTest, TestStateChange) {
+TEST(StateConditionTrackerTest, TestStateChange) {
int uid1 = 111;
int uid2 = 222;
@@ -60,7 +60,7 @@ TEST(StateTrackerTest, TestStateChange) {
trackerNameIndexMap[StringToId("UidProcState")] = 0;
vector<Matcher> primaryFields;
primaryFields.push_back(getSimpleMatcher(kUidProcTag, 1));
- StateTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(),
+ StateConditionTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(),
trackerNameIndexMap, primaryFields);
LogEvent event(kUidProcTag, 0 /*timestamp*/);
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index b98dc60086ac..325e869e5a9b 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -96,6 +96,11 @@ TEST(ConfigTtlE2eTest, TestCountMetric) {
EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
processor->mMetricsManagers.begin()->second->getTtlEndNs());
+
+ // Clear the data stored on disk as a result of the ttl.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
+ ADB_DUMP, FAST, &buffer);
}
diff --git a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
new file mode 100644
index 000000000000..5c9636fa99cc
--- /dev/null
+++ b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SurfaceflingerStatsPuller_test"
+
+#include "src/external/SurfaceflingerStatsPuller.h"
+
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class TestableSurfaceflingerStatsPuller : public SurfaceflingerStatsPuller {
+public:
+ TestableSurfaceflingerStatsPuller(const int tagId) : SurfaceflingerStatsPuller(tagId){};
+
+ void injectStats(const StatsProvider& statsProvider) {
+ mStatsProvider = statsProvider;
+ }
+};
+
+class SurfaceflingerStatsPullerTest : public ::testing::Test {
+public:
+ SurfaceflingerStatsPullerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~SurfaceflingerStatsPullerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+};
+
+TEST_F(SurfaceflingerStatsPullerTest, pullGlobalStats) {
+ surfaceflinger::SFTimeStatsGlobalProto proto;
+ proto.set_total_frames(1);
+ proto.set_missed_frames(2);
+ proto.set_client_composition_frames(2);
+ proto.set_display_on_time(4);
+
+ auto bucketOne = proto.add_present_to_present();
+ bucketOne->set_time_millis(2);
+ bucketOne->set_frame_count(4);
+ auto bucketTwo = proto.add_present_to_present();
+ bucketTwo->set_time_millis(4);
+ bucketTwo->set_frame_count(1);
+ auto bucketThree = proto.add_present_to_present();
+ bucketThree->set_time_millis(1000);
+ bucketThree->set_frame_count(1);
+ static constexpr int64_t expectedAnimationMillis = 12;
+ TestableSurfaceflingerStatsPuller puller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+
+ puller.injectStats([&] {
+ return proto.SerializeAsString();
+ });
+ puller.ForceClearCache();
+ vector<std::shared_ptr<LogEvent>> outData;
+ puller.Pull(&outData);
+
+ ASSERT_EQ(1, outData.size());
+ EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, outData[0]->GetTagId());
+ EXPECT_EQ(proto.total_frames(), outData[0]->getValues()[0].mValue.long_value);
+ EXPECT_EQ(proto.missed_frames(), outData[0]->getValues()[1].mValue.long_value);
+ EXPECT_EQ(proto.client_composition_frames(), outData[0]->getValues()[2].mValue.long_value);
+ EXPECT_EQ(proto.display_on_time(), outData[0]->getValues()[3].mValue.long_value);
+ EXPECT_EQ(expectedAnimationMillis, outData[0]->getValues()[4].mValue.long_value);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
new file mode 100644
index 000000000000..c89ffea85709
--- /dev/null
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2019, 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 <gtest/gtest.h>
+#include "state/StateManager.h"
+#include "state/StateTracker.h"
+#include "state/StateListener.h"
+
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Mock StateListener class for testing.
+ * Stores primary key and state pairs.
+ */
+class TestStateListener : public virtual StateListener {
+public:
+ TestStateListener(){};
+
+ virtual ~TestStateListener(){};
+
+ struct Update {
+ Update(const HashableDimensionKey& key, int state) : mKey(key), mState(state){};
+ HashableDimensionKey mKey;
+ int mState;
+ };
+
+ std::vector<Update> updates;
+
+ void onStateChanged(int stateAtomId, const HashableDimensionKey& primaryKey, int oldState,
+ int newState) {
+ updates.emplace_back(primaryKey, newState);
+ }
+};
+
+// START: build event functions.
+// State with no primary fields - ScreenStateChanged
+std::shared_ptr<LogEvent> buildScreenEvent(int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+// State with one primary field - UidProcessStateChanged
+std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+// State with multiple primary fields - OverlayStateChanged
+std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write(packageName);
+ event->write(true); // using_alert_window
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write(packageName);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+// END: build event functions.
+
+// START: get primary key functions
+void getUidProcessKey(int uid, HashableDimensionKey* key) {
+ int pos1[] = {1, 0, 0};
+ Field field1(27 /* atom id */, pos1, 0 /* depth */);
+ Value value1((int32_t)uid);
+
+ key->addValue(FieldValue(field1, value1));
+}
+
+void getOverlayKey(int uid, string packageName, HashableDimensionKey* key) {
+ int pos1[] = {1, 0, 0};
+ int pos2[] = {2, 0, 0};
+
+ Field field1(59 /* atom id */, pos1, 0 /* depth */);
+ Field field2(59 /* atom id */, pos2, 0 /* depth */);
+
+ Value value1((int32_t)uid);
+ Value value2(packageName);
+
+ key->addValue(FieldValue(field1, value1));
+ key->addValue(FieldValue(field2, value2));
+}
+// END: get primary key functions
+
+TEST(StateListenerTest, TestStateListenerWeakPointer) {
+ sp<TestStateListener> listener = new TestStateListener();
+ wp<TestStateListener> wListener = listener;
+ listener = nullptr; // let go of listener
+ EXPECT_TRUE(wListener.promote() == nullptr);
+}
+
+TEST(StateManagerTest, TestStateManagerGetInstance) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager& mgr = StateManager::getInstance();
+
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+}
+
+/**
+ * Test registering listeners to StateTrackers
+ *
+ * - StateManager will create a new StateTracker if it doesn't already exist
+ * and then register the listener to the StateTracker.
+ * - If a listener is already registered to a StateTracker, it is not added again.
+ * - StateTrackers are only created for atoms that are state atoms.
+ */
+TEST(StateTrackerTest, TestRegisterListener) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ StateManager mgr;
+
+ // Register listener to non-existing StateTracker
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register listener to existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register already registered listener to existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register listener to non-state atom
+ mgr.registerListener(android::util::BATTERY_LEVEL_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+}
+
+/**
+ * Test unregistering listeners from StateTrackers
+ *
+ * - StateManager will unregister listeners from a StateTracker only if the
+ * StateTracker exists and the listener is registered to the StateTracker.
+ * - Once all listeners are removed from a StateTracker, the StateTracker
+ * is also removed.
+ */
+TEST(StateTrackerTest, TestUnregisterListener) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ StateManager mgr;
+
+ // Unregister listener from non-existing StateTracker
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister non-registered listener from existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister second-to-last listener from StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister last listener from StateTracker
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states without primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event =
+ buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
+ EXPECT_EQ(2, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
+ EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, queryKey));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states with primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event = buildUidProcessEvent(
+ 1000,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1002, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey;
+ getUidProcessKey(1000, &queryKey);
+ EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey));
+}
+
+TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event = buildOverlayEvent(1000, "package1", 1); // state: ENTERED
+ mgr.onLogEvent(*event);
+
+ // check listener update
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener1->updates[0].mState);
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged
+ * when there is an error extracting state from log event. Listener is not
+ * updated of state change.
+ */
+TEST(StateTrackerTest, TestStateChangeEventError) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event =
+ buildIncorrectOverlayEvent(1000, "package1", 1); // state: ENTERED
+ mgr.onLogEvent(*event);
+
+ // check listener update
+ EXPECT_EQ(0, listener1->updates.size());
+}
+
+TEST(StateTrackerTest, TestStateQuery) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ sp<TestStateListener> listener3 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener2);
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener3);
+
+ std::shared_ptr<LogEvent> event1 = buildUidProcessEvent(
+ 1000,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::shared_ptr<LogEvent> event2 = buildUidProcessEvent(
+ 1001,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE); // state value: 1003
+ std::shared_ptr<LogEvent> event3 = buildUidProcessEvent(
+ 1002,
+ android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT); // state value: 1000
+ std::shared_ptr<LogEvent> event4 = buildUidProcessEvent(
+ 1001,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::shared_ptr<LogEvent> event5 =
+ buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON); // state value:
+ std::shared_ptr<LogEvent> event6 = buildOverlayEvent(1000, "package1", 1);
+ std::shared_ptr<LogEvent> event7 = buildOverlayEvent(1000, "package2", 2);
+
+ mgr.onLogEvent(*event1);
+ mgr.onLogEvent(*event2);
+ mgr.onLogEvent(*event3);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event6);
+ mgr.onLogEvent(*event7);
+
+ // Query for UidProcessState of uid 1001
+ HashableDimensionKey queryKey1;
+ getUidProcessKey(1001, &queryKey1);
+ EXPECT_EQ(1003, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for UidProcessState of uid 1004 - not in state map
+ HashableDimensionKey queryKey2;
+ getUidProcessKey(1004, &queryKey2);
+ EXPECT_EQ(-1,
+ mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey2)); // default state
+
+ // Query for UidProcessState of uid 1001 - after change in state
+ mgr.onLogEvent(*event4);
+ EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for ScreenState
+ EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+
+ // Query for OverlayState of uid 1000, package name "package2"
+ HashableDimensionKey queryKey3;
+ getOverlayKey(1000, "package2", &queryKey3);
+ EXPECT_EQ(2, mgr.getState(android::util::OVERLAY_STATE_CHANGED, queryKey3));
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index e0f7d862e70a..c9f069d62003 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -65,11 +65,21 @@ public final class Telecom extends BaseCommand {
private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+ /**
+ * Change the system dialer package name if a package name was specified,
+ * Example: adb shell telecom set-system-dialer <PACKAGE>
+ *
+ * Restore it to the default if if argument is "default" or no argument is passed.
+ * Example: adb shell telecom set-system-dialer default
+ */
+ private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer";
private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
private static final String COMMAND_SET_SIM_COUNT = "set-sim-count";
private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config";
private static final String COMMAND_GET_MAX_PHONES = "get-max-phones";
+ private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER =
+ "set-test-emergency-phone-account-package-filter";
private ComponentName mComponent;
private String mAccountId;
@@ -83,7 +93,10 @@ public final class Telecom extends BaseCommand {
+ "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
+ "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
+ "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
- + "usage: telecom set-user-selected-outgoing-phone-account <COMPONENT> <ID> "
+ + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>"
+ + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION"
+ + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n"
+ + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> "
+ "<USER_SN>\n"
+ "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
+ "usage: telecom set-test-call-screening-app <PACKAGE>\n"
@@ -100,6 +113,7 @@ public final class Telecom extends BaseCommand {
+ "usage: telecom set-sim-count <COUNT>\n"
+ "usage: telecom get-sim-config\n"
+ "usage: telecom get-max-phones\n"
+ + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ "\n"
+ "telecom set-phone-account-enabled: Enables the given phone account, if it has"
+ " already been registered with Telecom.\n"
@@ -113,6 +127,8 @@ public final class Telecom extends BaseCommand {
+ "telecom get-default-dialer: Displays the current default dialer.\n"
+ "\n"
+ "telecom get-system-dialer: Displays the current system dialer.\n"
+ + "telecom set-system-dialer: Set the override system dialer to the given"
+ + " component. To remove the override, send \"default\"\n"
+ "\n"
+ "telecom wait-on-handlers: Wait until all handlers finish their work.\n"
+ "\n"
@@ -123,6 +139,10 @@ public final class Telecom extends BaseCommand {
+ " or \"\" for single SIM\n"
+ "\n"
+ "telecom get-max-phones: Get the max supported phones from the modem.\n"
+ + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a"
+ + " package name that will be used for test emergency calls. To clear,"
+ + " send an empty package name. Real emergency calls will still be placed"
+ + " over Telephony.\n"
);
}
@@ -193,6 +213,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_GET_DEFAULT_DIALER:
runGetDefaultDialer();
break;
+ case COMMAND_SET_SYSTEM_DIALER:
+ runSetSystemDialer();
+ break;
case COMMAND_GET_SYSTEM_DIALER:
runGetSystemDialer();
break;
@@ -208,6 +231,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_GET_MAX_PHONES:
runGetMaxPhones();
break;
+ case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER:
+ runSetEmergencyPhoneAccountPackageFilter();
+ break;
default:
Log.w(this, "onRun: unknown command: %s", command);
throw new IllegalArgumentException ("unknown command '" + command + "'");
@@ -234,19 +260,31 @@ public final class Telecom extends BaseCommand {
}
private void runRegisterSimPhoneAccount() throws RemoteException {
+ boolean isEmergencyAccount = false;
+ String opt;
+ while ((opt = nextOption()) != null) {
+ switch (opt) {
+ case "-e": {
+ isEmergencyAccount = true;
+ break;
+ }
+ }
+ }
final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
final String label = nextArgRequired();
final String address = nextArgRequired();
+ int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+ | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0);
PhoneAccount account = PhoneAccount.builder(
handle, label)
- .setAddress(Uri.parse(address))
- .setSubscriptionAddress(Uri.parse(address))
- .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
- PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
- .setShortDescription(label)
- .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
- .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
- .build();
+ .setAddress(Uri.parse(address))
+ .setSubscriptionAddress(Uri.parse(address))
+ .setCapabilities(capabilities)
+ .setShortDescription(label)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+ .build();
mTelecomService.registerPhoneAccount(account);
System.out.println("Success - " + handle + " registered.");
}
@@ -297,6 +335,14 @@ public final class Telecom extends BaseCommand {
System.out.println("Success - " + packageName + " set as override default dialer.");
}
+ private void runSetSystemDialer() throws RemoteException {
+ final String flatComponentName = nextArg();
+ final ComponentName componentName = (flatComponentName.equals("default")
+ ? null : parseComponentName(flatComponentName));
+ mTelecomService.setSystemDialer(componentName);
+ System.out.println("Success - " + componentName + " set as override system dialer.");
+ }
+
private void runGetDefaultDialer() throws RemoteException {
System.out.println(mTelecomService.getDefaultDialerPackage());
}
@@ -338,6 +384,18 @@ public final class Telecom extends BaseCommand {
}
}
+ private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
+ String packageName = mArgs.getNextArg();
+ if (TextUtils.isEmpty(packageName)) {
+ mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null);
+ System.out.println("Success - filter cleared");
+ } else {
+ mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName);
+ System.out.println("Success = filter set to " + packageName);
+ }
+
+ }
+
private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
if (TextUtils.isEmpty(mArgs.peekNextArg())) {
return null;