summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/bootanimation/BootAnimation.cpp69
-rw-r--r--cmds/bootanimation/BootAnimation.h4
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp8
-rw-r--r--cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl1
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp4
-rw-r--r--cmds/idmap2/libidmap2/Policies.cpp1
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp17
-rw-r--r--cmds/idmap2/tests/FileUtilsTests.cpp22
-rw-r--r--cmds/idmap2/tests/Idmap2BinaryTests.cpp8
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp102
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp4
-rwxr-xr-x[-rw-r--r--]cmds/idmap2/tests/data/overlay/build2
-rw-r--r--cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml22
-rwxr-xr-xcmds/idmap2/tests/data/signature-overlay/build26
-rw-r--r--cmds/idmap2/tests/data/signature-overlay/res/values/values.xml20
-rw-r--r--cmds/idmap2/tests/data/signature-overlay/signature-overlay.apkbin0 -> 1183 bytes
-rwxr-xr-x[-rw-r--r--]cmds/idmap2/tests/data/system-overlay-invalid/build0
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml1
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apkbin1511 -> 1583 bytes
-rwxr-xr-x[-rw-r--r--]cmds/idmap2/tests/data/system-overlay/build0
-rwxr-xr-x[-rw-r--r--]cmds/idmap2/tests/data/target/build2
-rw-r--r--cmds/idmap2/tests/data/target/res/values/overlayable.xml36
-rw-r--r--cmds/idmap2/tests/data/target/res/values/values.xml1
-rw-r--r--cmds/idmap2/tests/data/target/target-no-overlayable.apkbin2075 -> 2139 bytes
-rw-r--r--cmds/idmap2/tests/data/target/target.apkbin4761 -> 4853 bytes
-rw-r--r--cmds/statsd/Android.bp2
-rw-r--r--cmds/statsd/src/FieldValue.cpp19
-rw-r--r--cmds/statsd/src/FieldValue.h3
-rw-r--r--cmds/statsd/src/StatsService.cpp56
-rw-r--r--cmds/statsd/src/StatsService.h8
-rw-r--r--cmds/statsd/src/anomaly/AlarmTracker.cpp4
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp14
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.h8
-rw-r--r--cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp8
-rw-r--r--cmds/statsd/src/anomaly/subscriber_util.cpp13
-rw-r--r--cmds/statsd/src/anomaly/subscriber_util.h7
-rw-r--r--cmds/statsd/src/atoms.proto118
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp13
-rw-r--r--cmds/statsd/src/external/TrainInfoPuller.cpp53
-rw-r--r--cmds/statsd/src/external/TrainInfoPuller.h38
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp7
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h10
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp31
-rw-r--r--cmds/statsd/src/logd/LogEvent.h13
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp4
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp7
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h1
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp14
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp6
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h4
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp22
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h4
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp100
-rw-r--r--cmds/statsd/src/packages/UidMap.h15
-rw-r--r--cmds/statsd/src/stats_log.proto15
-rw-r--r--cmds/statsd/src/stats_log_util.cpp7
-rw-r--r--cmds/statsd/src/stats_log_util.h2
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp68
-rw-r--r--cmds/statsd/src/storage/StorageManager.h17
-rw-r--r--cmds/statsd/src/subscriber/IncidentdReporter.cpp72
-rw-r--r--cmds/statsd/src/subscriber/IncidentdReporter.h4
-rw-r--r--cmds/statsd/statsd.rc1
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp95
-rw-r--r--cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp3
-rw-r--r--cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp81
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp46
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp16
-rw-r--r--cmds/statsd/tests/storage/StorageManager_test.cpp52
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java28
70 files changed, 1232 insertions, 229 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 46917e4f6062..a6c7cae9bdb6 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -110,13 +110,30 @@ BootAnimation::BootAnimation(sp<Callbacks> callbacks)
} else {
mShuttingDown = true;
}
+ ALOGD("%sAnimationStartTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
+ elapsedRealtime());
+}
+
+BootAnimation::~BootAnimation() {
+ if (mAnimation != nullptr) {
+ releaseAnimation(mAnimation);
+ mAnimation = nullptr;
+ }
+ ALOGD("%sAnimationStopTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
+ elapsedRealtime());
}
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
- run("BootAnimation", PRIORITY_DISPLAY);
+ // Load the animation content -- this can be slow (eg 200ms)
+ // called before waitForSurfaceFlinger() in main() to avoid wait
+ ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
+ mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
+ preloadAnimation();
+ ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
+ mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
}
}
@@ -306,6 +323,20 @@ status_t BootAnimation::readyToRun() {
mFlingerSurface = s;
mTargetInset = -1;
+ return NO_ERROR;
+}
+
+bool BootAnimation::preloadAnimation() {
+ findBootAnimationFile();
+ if (!mZipFileName.isEmpty()) {
+ mAnimation = loadAnimation(mZipFileName);
+ return (mAnimation != nullptr);
+ }
+
+ return false;
+}
+
+void BootAnimation::findBootAnimationFile() {
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
@@ -320,7 +351,7 @@ status_t BootAnimation::readyToRun() {
for (const char* f : encryptedBootFiles) {
if (access(f, R_OK) == 0) {
mZipFileName = f;
- return NO_ERROR;
+ return;
}
}
}
@@ -332,10 +363,9 @@ status_t BootAnimation::readyToRun() {
for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
if (access(f, R_OK) == 0) {
mZipFileName = f;
- return NO_ERROR;
+ return;
}
}
- return NO_ERROR;
}
bool BootAnimation::threadLoop()
@@ -790,8 +820,6 @@ bool BootAnimation::preloadZip(Animation& animation)
}
}
- mCallbacks->init(animation.parts);
-
zip->endIteration(cookie);
return true;
@@ -799,13 +827,25 @@ bool BootAnimation::preloadZip(Animation& animation)
bool BootAnimation::movie()
{
- Animation* animation = loadAnimation(mZipFileName);
- if (animation == NULL)
+ if (mAnimation == nullptr) {
+ mAnimation = loadAnimation(mZipFileName);
+ }
+
+ if (mAnimation == nullptr)
return false;
+ // mCallbacks->init() may get called recursively,
+ // this loop is needed to get the same results
+ for (const Animation::Part& part : mAnimation->parts) {
+ if (part.animation != nullptr) {
+ mCallbacks->init(part.animation->parts);
+ }
+ }
+ mCallbacks->init(mAnimation->parts);
+
bool anyPartHasClock = false;
- for (size_t i=0; i < animation->parts.size(); i++) {
- if(validClock(animation->parts[i])) {
+ for (size_t i=0; i < mAnimation->parts.size(); i++) {
+ if(validClock(mAnimation->parts[i])) {
anyPartHasClock = true;
break;
}
@@ -846,7 +886,7 @@ bool BootAnimation::movie()
bool clockFontInitialized = false;
if (mClockEnabled) {
clockFontInitialized =
- (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
+ (initFont(&mAnimation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
mClockEnabled = clockFontInitialized;
}
@@ -855,7 +895,7 @@ bool BootAnimation::movie()
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
}
- playAnimation(*animation);
+ playAnimation(*mAnimation);
if (mTimeCheckThread != nullptr) {
mTimeCheckThread->requestExit();
@@ -863,10 +903,11 @@ bool BootAnimation::movie()
}
if (clockFontInitialized) {
- glDeleteTextures(1, &animation->clockFont.texture.name);
+ glDeleteTextures(1, &mAnimation->clockFont.texture.name);
}
- releaseAnimation(animation);
+ releaseAnimation(mAnimation);
+ mAnimation = nullptr;
return false;
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 19616cb790c7..dc19fb09ef1d 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -115,6 +115,7 @@ public:
};
explicit BootAnimation(sp<Callbacks> callbacks);
+ virtual ~BootAnimation();
sp<SurfaceComposerClient> session() const;
@@ -155,6 +156,8 @@ private:
void releaseAnimation(Animation*) const;
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
+ void findBootAnimationFile();
+ bool preloadAnimation();
void checkExit();
@@ -182,6 +185,7 @@ private:
SortedVector<String8> mLoadedFiles;
sp<TimeCheckThread> mTimeCheckThread = nullptr;
sp<Callbacks> mCallbacks;
+ Animation* mAnimation = nullptr;
};
// ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index a52a5e92a840..6c7b3e51ff8d 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -44,14 +44,16 @@ int main()
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
+ // create the boot animation object (may take up to 200ms for 2MB zip)
+ sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
+
waitForSurfaceFlinger();
- // create the boot animation object
- sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
+ boot->run("BootAnimation", PRIORITY_DISPLAY);
+
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
- ALOGV("Boot animation exit");
return 0;
}
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index ea7274f3ea58..4a66715ad2b8 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -24,6 +24,7 @@ interface IIdmap2 {
const int POLICY_SYSTEM_PARTITION = 0x00000002;
const int POLICY_VENDOR_PARTITION = 0x00000004;
const int POLICY_PRODUCT_PARTITION = 0x00000008;
+ const int POLICY_SIGNATURE = 0x00000010;
@utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 99b5f0ff3c2d..ec498ffb393c 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -284,7 +284,7 @@ std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
bool CheckOverlayable(const LoadedPackage& target_package,
const utils::OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_polices, const ResourceId& resid) {
+ const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
if (overlayable_info == nullptr) {
// If the resource does not have an overlayable definition, allow the resource to be overlaid.
@@ -299,7 +299,7 @@ bool CheckOverlayable(const LoadedPackage& target_package,
}
// Enforce policy restrictions if the resource is declared as overlayable.
- return (overlayable_info->policy_flags & fulfilled_polices) != 0;
+ return (overlayable_info->policy_flags & fulfilled_policies) != 0;
}
std::unique_ptr<const Idmap> Idmap::FromApkAssets(
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
index 0f87ef0c4ea9..6649288dfa41 100644
--- a/cmds/idmap2/libidmap2/Policies.cpp
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -35,6 +35,7 @@ const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
{"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
{"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
{"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
+ {"signature", PolicyFlags::POLICY_SIGNATURE},
};
} // namespace
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 0e0e25f4f0f3..9a0412efbde4 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -129,28 +129,31 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) {
success = LoadedIdmap::Lookup(header, 0x0008, &entry); // string/policy_system_vendor
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/str1
+ success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/policy_signature
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/str1
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0000);
- success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/str2
+ success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/str2
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/str3
+ success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/str3
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0001);
- success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/str4
+ success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/str4
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0002);
- success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/x
+ success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/x
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/y
+ success = LoadedIdmap::Lookup(header, 0x000f, &entry); // string/y
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x000f, &entry); // string/z
+ success = LoadedIdmap::Lookup(header, 0x0010, &entry); // string/z
ASSERT_FALSE(success);
}
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 8514e12e8c17..2e85eb6215d1 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -39,12 +39,13 @@ TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) {
[](unsigned char type ATTRIBUTE_UNUSED,
const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 6U);
+ ASSERT_EQ(v->size(), 7U);
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({
root + "/.",
root + "/..",
root + "/overlay",
root + "/target",
+ root + "/signature-overlay",
root + "/system-overlay",
root + "/system-overlay-invalid",
}));
@@ -56,15 +57,22 @@ TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
});
ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 9U);
+ ASSERT_EQ(v->size(), 10U);
ASSERT_EQ(
std::set<std::string>(v->begin(), v->end()),
std::set<std::string>(
- {root + "/target/target.apk", root + "/target/target-no-overlayable.apk",
- root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk",
- root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-static-1.apk",
- root + "/overlay/overlay-static-2.apk", root + "/system-overlay/system-overlay.apk",
- root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
+ {
+ root + "/target/target.apk",
+ root + "/target/target-no-overlayable.apk",
+ root + "/overlay/overlay.apk",
+ root + "/overlay/overlay-no-name.apk",
+ root + "/overlay/overlay-no-name-static.apk",
+ root + "/overlay/overlay-static-1.apk",
+ root + "/overlay/overlay-static-2.apk",
+ root + "/signature-overlay/signature-overlay.apk",
+ root + "/system-overlay/system-overlay.apk",
+ root + "/system-overlay-invalid/system-overlay-invalid.apk"
+ }));
}
TEST(FileUtilsTests, ReadFile) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 1216f9ec736a..a6a2ada76712 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -132,9 +132,9 @@ TEST_F(Idmap2BinaryTests, Dump) {
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
- ASSERT_NE(result->stdout.find("0x7f020009 -> 0x7f020000 string/str1"), std::string::npos);
- ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020001 string/str3"), std::string::npos);
- ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020002 string/str4"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020000 string/str1"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020001 string/str3"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f02000d -> 0x7f020002 string/str4"), std::string::npos);
ASSERT_EQ(result->stdout.find("00000210: 007f target package id"), std::string::npos);
// clang-format off
@@ -286,7 +286,7 @@ TEST_F(Idmap2BinaryTests, Lookup) {
"lookup",
"--idmap-path", GetIdmapPath(),
"--config", "",
- "--resid", "0x7f020009"}); // string/str1
+ "--resid", "0x7f02000a"}); // string/str1
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index b40521f054af..53ec03ba3d5e 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -191,8 +191,8 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
- ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xdd53ca29);
- ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xa71ccd77);
+ ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xd513ca1b);
+ ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x8635c2ed);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -217,7 +217,7 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetEntryCount(), 4U);
- ASSERT_EQ(types[1]->GetEntryOffset(), 9U);
+ ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
@@ -254,11 +254,76 @@ TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
- ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 4U);
ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_public
- ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_system
- ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_system_vendor
+ ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_signature
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0001U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0002U); // string/policy_system_vendor
+}
+
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignature) {
+ const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ const std::string overlay_apk_path(GetTestDataPath() + "/signature-overlay/signature-overlay.apk");
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE;
+
+ std::stringstream error;
+ std::unique_ptr<const Idmap> idmap =
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ policy_flags, /* enforce_overlayable */ true, error);
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 1U);
+
+ ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+ ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 1U);
+ ASSERT_EQ(types[0]->GetEntryOffset(), 7U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_signature
+}
+
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignatureNotFulfilled) {
+ const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ const std::string overlay_apk_path(GetTestDataPath() + "/signature-overlay/signature-overlay.apk");
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC;
+
+ std::stringstream error;
+ std::unique_ptr<const Idmap> idmap =
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ policy_flags, /* enforce_overlayable */ true, error);
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 0U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 0U); // can't overlay, so contains nothing
}
// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
@@ -292,11 +357,12 @@ TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
- ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 4U);
ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
ASSERT_EQ(types[0]->GetEntry(0), 0x0003U); // string/policy_public
- ASSERT_EQ(types[0]->GetEntry(1), 0x0004U); // string/policy_system
- ASSERT_EQ(types[0]->GetEntry(2), 0x0005U); // string/policy_system_vendor
+ ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_signature
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0005U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0006U); // string/policy_system_vendor
}
// Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled.
@@ -330,14 +396,15 @@ TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgn
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
- ASSERT_EQ(types[0]->GetEntryCount(), 6U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 7U);
ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/other
ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_product
- ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_public
- ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system
- ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system_vendor
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_signature
+ ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_public
+ ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_system_vendor
}
// The resources of APKs that do not include an overlayable declaration should not restrict what
@@ -371,14 +438,15 @@ TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayable) {
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
- ASSERT_EQ(types[0]->GetEntryCount(), 6U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 7U);
ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/other
ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_product
ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_public
- ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system
- ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system_vendor
+ ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/string/policy_signature
+ ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_system_vendor
}
// The resources of APKs that do not include an overlayable declaration should not restrict what
@@ -418,7 +486,7 @@ TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayableAndNoTar
ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetEntryCount(), 4U);
- ASSERT_EQ(types[1]->GetEntryOffset(), 9U);
+ ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index a5588c330d85..7ec13ed0ade7 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -52,8 +52,8 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
ASSERT_NE(stream.str().find("00000004: 00000001 version\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000008: dd53ca29 target crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000000c: a71ccd77 overlay crc\n"), std::string::npos);
+ ASSERT_NE(stream.str().find("00000008: d513ca1b target crc\n"), std::string::npos);
+ ASSERT_NE(stream.str().find("0000000c: 8635c2ed overlay crc\n"), std::string::npos);
ASSERT_NE(stream.str().find("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"),
std::string::npos);
}
diff --git a/cmds/idmap2/tests/data/overlay/build b/cmds/idmap2/tests/data/overlay/build
index e60da803388b..e879f443c7b1 100644..100755
--- a/cmds/idmap2/tests/data/overlay/build
+++ b/cmds/idmap2/tests/data/overlay/build
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FRAMEWORK_RES_APK="$(gettop)/out/target/common/obj/APPS/framework-res_intermediates/package-export.apk"
+FRAMEWORK_RES_APK="${ANDROID_BUILD_TOP}/out/target/common/obj/APPS/framework-res_intermediates/package-export.apk"
aapt2 compile --dir res -o compiled.flata
diff --git a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
new file mode 100644
index 000000000000..5dacebded529
--- /dev/null
+++ b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test.overlay.system">
+ <overlay
+ android:targetPackage="test.target"
+ android:targetName="TestResources"/>
+</manifest>
diff --git a/cmds/idmap2/tests/data/signature-overlay/build b/cmds/idmap2/tests/data/signature-overlay/build
new file mode 100755
index 000000000000..fdd8301c3b7d
--- /dev/null
+++ b/cmds/idmap2/tests/data/signature-overlay/build
@@ -0,0 +1,26 @@
+# 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+ --no-resource-removal \
+ -I "$FRAMEWORK_RES_APK" \
+ --manifest AndroidManifest.xml \
+ -o signature-overlay.apk \
+ compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/signature-overlay/res/values/values.xml b/cmds/idmap2/tests/data/signature-overlay/res/values/values.xml
new file mode 100644
index 000000000000..59e7d8ed69c1
--- /dev/null
+++ b/cmds/idmap2/tests/data/signature-overlay/res/values/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+ <!-- This overlay will fulfill the policy "signature". This allows it overlay the
+ following resources. -->
+ <string name="policy_signature">policy_signature</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
new file mode 100644
index 000000000000..b2c490dcbb90
--- /dev/null
+++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
index 920e1f8ad6f3..920e1f8ad6f3 100644..100755
--- a/cmds/idmap2/tests/data/system-overlay-invalid/build
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
index af1bea16daee..02704009d743 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -22,6 +22,7 @@
<!-- Requests to overlay a resource that belongs to a policy the overlay does not fulfill. -->
<string name="policy_product">policy_product</string>
+ <string name="policy_signature">policy_signature</string>
<!-- Requests to overlay a resource that is not declared as overlayable. -->
<string name="not_overlayable">not_overlayable</string>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
index 710ed9067f69..9448939b5636 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
index be0d2390f535..be0d2390f535 100644..100755
--- a/cmds/idmap2/tests/data/system-overlay/build
+++ b/cmds/idmap2/tests/data/system-overlay/build
diff --git a/cmds/idmap2/tests/data/target/build b/cmds/idmap2/tests/data/target/build
index 137ddb5ecaa1..e6df742cc9da 100644..100755
--- a/cmds/idmap2/tests/data/target/build
+++ b/cmds/idmap2/tests/data/target/build
@@ -17,5 +17,5 @@ aapt2 link --manifest AndroidManifest.xml -A assets -o target.apk compiled.flata
rm compiled.flata
aapt2 compile res/values/values.xml -o .
-aapt2 link --manifest AndroidManifest.xml -A assets -o target_no_overlayable.apk values_values.arsc.flat
+aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat
rm values_values.arsc.flat \ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index 02d25630546f..0bf83fa50b75 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -15,20 +15,12 @@
-->
<resources>
<overlayable name="TestResources">
- <!-- Publicly overlayable resources -->
- <item type="string" name="a" />
- <item type="string" name="b" />
- <item type="string" name="c" />
- <item type="string" name="str1" />
- <item type="string" name="str2" />
- <item type="string" name="str3" />
- <item type="string" name="str4" />
- <item type="string" name="x" />
- <item type="string" name="y" />
- <item type="string" name="z" />
- <item type="integer" name="int1" />
-
- <!-- Resources with partition restrictins -->
+ <!-- Resources with signature restrictions -->
+ <policy type="signature">
+ <item type="string" name="policy_signature" />
+ </policy>
+
+ <!-- Resources with partition restrictions -->
<policy type="system">
<item type="string" name="policy_system" />
</policy>
@@ -41,12 +33,26 @@
<item type="string" name="policy_product" />
</policy>
+ <!-- Resources publicly overlayable -->
<policy type="public">
<item type="string" name="policy_public" />
+ <item type="string" name="a" />
+ <item type="string" name="b" />
+ <item type="string" name="c" />
+ <item type="string" name="str1" />
+ <item type="string" name="str2" />
+ <item type="string" name="str3" />
+ <item type="string" name="str4" />
+ <item type="string" name="x" />
+ <item type="string" name="y" />
+ <item type="string" name="z" />
+ <item type="integer" name="int1" />
</policy>
</overlayable>
<overlayable name="OtherResources">
- <item type="string" name="other" />
+ <policy type="public">
+ <item type="string" name="other" />
+ </policy>
</overlayable>
</resources> \ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 0d337f3890a8..edd53f4c9b52 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -33,6 +33,7 @@
<string name="policy_system_vendor">policy_system_vendor</string>
<string name="policy_product">policy_product</string>
<string name="policy_public">policy_public</string>
+ <string name="policy_signature">policy_signature</string>
<item type="string" name="other" />
</resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 8676cbb9dc3f..908b54a2f0c3 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index ecbe87578684..da3c1aef5fba 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index faf2053835fa..f4086557870d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -76,6 +76,7 @@ cc_defaults {
"src/external/SubsystemSleepStatePuller.cpp",
"src/external/PowerStatsPuller.cpp",
"src/external/ResourceHealthManagerPuller.cpp",
+ "src/external/TrainInfoPuller.cpp",
"src/external/StatsPullerManager.cpp",
"src/external/puller_util.cpp",
"src/logd/LogEvent.cpp",
@@ -238,6 +239,7 @@ cc_test {
"tests/guardrail/StatsdStats_test.cpp",
"tests/metrics/metrics_test_helper.cpp",
"tests/statsd_test_util.cpp",
+ "tests/storage/StorageManager_test.cpp",
"tests/e2e/WakelockDuration_e2e_test.cpp",
"tests/e2e/MetricActivation_e2e_test.cpp",
"tests/e2e/MetricConditionLink_e2e_test.cpp",
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 80ed80776829..13f5c8ae5fd8 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -19,6 +19,7 @@
#include "FieldValue.h"
#include "HashableDimensionKey.h"
#include "math.h"
+#include "statslog.h"
namespace android {
namespace os {
@@ -122,6 +123,24 @@ bool isAttributionUidField(const FieldValue& value) {
return false;
}
+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;
+ }
+ }
+
+ return isUid ? value.mValue.int_value : -1;
+}
+
bool isAttributionUidField(const Field& field, const Value& value) {
int f = field.getField() & 0xff007f;
if (f == 0x10001 && value.getType() == INT) {
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index a5d00ac4e72b..6729e052b5ee 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -386,6 +386,9 @@ bool HasPositionALL(const FieldMatcher& matcher);
bool isAttributionUidField(const FieldValue& value);
+/* returns uid if the field is uid field, or -1 if the field is not a uid field */
+int getUidIfExists(const FieldValue& value);
+
void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
bool isAttributionUidField(const Field& field, const Value& value);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b478fed49a54..c542b6215c88 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -31,6 +31,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
@@ -47,6 +48,7 @@ using namespace android;
using android::base::StringPrintf;
using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_INT64;
using android::util::FIELD_TYPE_MESSAGE;
namespace android {
@@ -62,6 +64,8 @@ constexpr const char* kOpUsage = "android:get_usage_stats";
// for StatsDataDumpProto
const int FIELD_ID_REPORTS_LIST = 1;
+// for TrainInfo experiment id serialization
+const int FIELD_ID_EXPERIMENT_ID = 1;
static binder::Status ok() {
return binder::Status::ok();
@@ -155,7 +159,7 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
}
})) {
- mUidMap = new UidMap();
+ mUidMap = UidMap::getInstance();
mPullerManager = new StatsPullerManager();
StatsPuller::SetUidMap(mUidMap);
mConfigManager = new ConfigManager();
@@ -1167,6 +1171,56 @@ Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& p
return Status::ok();
}
+Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName,
+ int64_t trainVersionCode, int options,
+ int32_t state,
+ const std::vector<int64_t>& experimentIds) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ // For testing
+ if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
+ return ok();
+ }
+
+ // Caller must be granted these permissions
+ if (!checkCallingPermission(String16(kPermissionDump))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
+ }
+ if (!checkCallingPermission(String16(kPermissionUsage))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
+ }
+ // TODO: add verifier permission
+
+ userid_t userId = multiuser_get_user_id(uid);
+
+ bool requiresStaging = options | IStatsManager::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+
+ ProtoOutputStream proto;
+ for (const auto& expId : experimentIds) {
+ proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+ (long long)expId);
+ }
+
+ vector<uint8_t> buffer;
+ buffer.resize(proto.size());
+ size_t pos = 0;
+ auto iter = proto.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(buffer[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+ LogEvent event(std::string(String8(trainName).string()), trainVersionCode, requiresStaging,
+ rollbackEnabled, requiresLowLatencyMonitor, state, buffer, userId);
+ mProcessor->OnLogEvent(&event);
+ StorageManager::writeTrainInfo(trainVersionCode, buffer);
+ return Status::ok();
+}
+
hardware::Return<void> StatsService::reportSpeakerImpedance(
const SpeakerImpedance& speakerImpedance) {
LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 7f10d74ec7d6..d24565a63054 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -31,6 +31,7 @@
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsManager.h>
#include <binder/IResultReceiver.h>
#include <utils/Looper.h>
@@ -186,6 +187,13 @@ public:
virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
/**
+ * Binder call to log BinaryPushStateChanged atom.
+ */
+ virtual Status sendBinaryPushStateChangedAtom(
+ const android::String16& trainName, int64_t trainVersionCode, int options,
+ int32_t state, const std::vector<int64_t>& experimentIds) override;
+
+ /**
* Binder call to get SpeakerImpedance atom.
*/
virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 8d7369935ea4..019a9f7e5f9a 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -78,8 +78,8 @@ void AlarmTracker::informAlarmsFired(
}
if (!mSubscriptions.empty()) {
VLOG("AlarmTracker triggers the subscribers.");
- triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
- mSubscriptions);
+ triggerSubscribers(mAlarmConfig.id(), 0 /*metricId N/A*/, DEFAULT_METRIC_DIMENSION_KEY,
+ 0 /* metricValue N/A */, mConfigKey, mSubscriptions);
}
firedAlarms.erase(mInternalAlarm);
mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index ee111cddcfd7..d1dcb5df7838 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -207,7 +207,8 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
}
-void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key) {
+void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, int64_t metricId,
+ const MetricDimensionKey& key, int64_t metricValue) {
// TODO(b/110563466): Why receive timestamp? RefractoryPeriod should always be based on
// real time right now.
if (isInRefractoryPeriod(timestampNs, key)) {
@@ -225,7 +226,7 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime
if (!mSubscriptions.empty()) {
ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
mAlert.id(), key.toString().c_str());
- informSubscribers(key);
+ informSubscribers(key, metricId, metricValue);
} else {
ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
}
@@ -238,11 +239,11 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime
}
void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
- const int64_t& currBucketNum,
+ const int64_t& currBucketNum, int64_t metricId,
const MetricDimensionKey& key,
const int64_t& currentBucketValue) {
if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
- declareAnomaly(timestampNs, key);
+ declareAnomaly(timestampNs, metricId, key, currentBucketValue);
}
}
@@ -255,8 +256,9 @@ bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs,
return false;
}
-void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
- triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions);
+void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id,
+ int64_t metricValue) {
+ triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions);
}
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 927e2df1b53a..e9414735b82b 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -67,14 +67,16 @@ public:
const int64_t& currentBucketValue);
// Informs incidentd about the detected alert.
- void declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key);
+ void declareAnomaly(const int64_t& timestampNs, int64_t metricId, const MetricDimensionKey& key,
+ int64_t metricValue);
// Detects if, based on past buckets plus the new currentBucketValue (which generally
// represents the partially-filled current bucket), an anomaly has happened, and if so,
// declares an anomaly and informs relevant subscribers.
// Also advances to currBucketNum-1.
void detectAndDeclareAnomaly(const int64_t& timestampNs, const int64_t& currBucketNum,
- const MetricDimensionKey& key, const int64_t& currentBucketValue);
+ int64_t metricId, const MetricDimensionKey& key,
+ const int64_t& currentBucketValue);
// Init the AlarmMonitor which is shared across anomaly trackers.
virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) {
@@ -176,7 +178,7 @@ protected:
virtual void resetStorage();
// Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred.
- void informSubscribers(const MetricDimensionKey& key);
+ void informSubscribers(const MetricDimensionKey& key, int64_t metricId, int64_t metricValue);
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index 3acfd171848e..2b56810170e5 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -65,7 +65,9 @@ void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey,
// If the alarm is set in the past but hasn't fired yet (due to lag), catch it now.
if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) {
- declareAnomaly(timestampNs, dimensionKey);
+ declareAnomaly(timestampNs, mAlert.metric_id(), dimensionKey,
+ mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) -
+ itr->second->timestampSec);
}
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->remove(itr->second);
@@ -100,7 +102,9 @@ void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs,
// Now declare each of these alarms to have fired.
for (const auto& kv : matchedAlarms) {
- declareAnomaly(timestampNs, kv.first);
+ declareAnomaly(
+ timestampNs, mAlert.metric_id(), kv.first,
+ mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - kv.second->timestampSec);
mAlarms.erase(kv.first);
firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it.
}
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 6b46b8b3b900..548a6869436d 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -30,9 +30,8 @@ namespace android {
namespace os {
namespace statsd {
-void triggerSubscribers(const int64_t rule_id,
- const MetricDimensionKey& dimensionKey,
- const ConfigKey& configKey,
+void triggerSubscribers(int64_t ruleId, int64_t metricId, const MetricDimensionKey& dimensionKey,
+ int64_t metricValue, const ConfigKey& configKey,
const std::vector<Subscription>& subscriptions) {
VLOG("informSubscribers called.");
if (subscriptions.empty()) {
@@ -50,13 +49,14 @@ void triggerSubscribers(const int64_t rule_id,
}
switch (subscription.subscriber_information_case()) {
case Subscription::SubscriberInformationCase::kIncidentdDetails:
- if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) {
+ if (!GenerateIncidentReport(subscription.incidentd_details(), ruleId, metricId,
+ dimensionKey, metricValue, configKey)) {
ALOGW("Failed to generate incident report.");
}
break;
case Subscription::SubscriberInformationCase::kPerfettoDetails:
if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
- subscription.id(), rule_id, configKey)) {
+ subscription.id(), ruleId, configKey)) {
ALOGW("Failed to generate perfetto traces.");
}
break;
@@ -66,7 +66,7 @@ void triggerSubscribers(const int64_t rule_id,
break;
case Subscription::SubscriberInformationCase::kPerfprofdDetails:
if (!CollectPerfprofdTraceAndUploadToDropbox(subscription.perfprofd_details(),
- rule_id, configKey)) {
+ ruleId, configKey)) {
ALOGW("Failed to generate perfprofd traces.");
}
break;
@@ -76,7 +76,6 @@ void triggerSubscribers(const int64_t rule_id,
}
}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/anomaly/subscriber_util.h b/cmds/statsd/src/anomaly/subscriber_util.h
index dba8981a72aa..1df3c8991f94 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.h
+++ b/cmds/statsd/src/anomaly/subscriber_util.h
@@ -24,10 +24,9 @@ namespace android {
namespace os {
namespace statsd {
-void triggerSubscribers(const int64_t rule_id,
- const MetricDimensionKey& dimensionKey,
- const ConfigKey& configKey,
- const std::vector<Subscription>& subscriptions);
+void triggerSubscribers(const int64_t ruleId, const int64_t metricId,
+ const MetricDimensionKey& dimensionKey, int64_t metricValue,
+ const ConfigKey& configKey, const std::vector<Subscription>& subscriptions);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 29f67c7e6f9b..d78647eebe1f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -245,6 +245,8 @@ message Atom {
AssistGestureStageReported assist_gesture_stage_reported = 174;
AssistGestureFeedbackReported assist_gesture_feedback_reported = 175;
AssistGestureProgressReported assist_gesture_progress_reported = 176;
+ TouchGestureClassified touch_gesture_classified = 177;
+ HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
}
// Pulled events will start at field 10000.
@@ -302,6 +304,8 @@ message Atom {
RoleHolder role_holder = 10049;
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
+ TimeZoneDataInfo time_zone_data_info = 10052;
+ SDCardInfo sdcard_info = 10053;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -2407,6 +2411,37 @@ message TouchEventReported {
}
/**
+ * Logs gesture classification and timing information for touch events.
+ *
+ * Logged from:
+ * frameworks/base/core/java/android/view/GestureDetector.java
+ * frameworks/base/core/java/android/view/View.java
+ */
+message TouchGestureClassified {
+ // The source of the classification (e.g. Java class name).
+ optional string source = 1;
+
+ enum Classification {
+ UNKNOWN_CLASSIFICATION = 0;
+ SINGLE_TAP = 1;
+ DOUBLE_TAP = 2;
+ LONG_PRESS = 3;
+ DEEP_PRESS = 4;
+ SCROLL = 5;
+ }
+ // The classification of the gesture.
+ optional Classification classification = 2;
+
+ // The interval from the start of a touch event stream until the
+ // classification was made.
+ optional int32 latency_millis = 3;
+
+ // The distance from the location of the first touch event to the
+ // location of the touch event when the classification was made.
+ optional float displacement_px = 4;
+}
+
+/**
* Logs that a setting was updated.
* Logged from:
* frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -3156,6 +3191,13 @@ message FlagFlipUpdateOccurred {
optional int64 order_id = 2;
}
+/**
+ * Potential experiment ids that goes with a train install.
+ */
+message TrainExperimentIds {
+ repeated int64 experiment_id = 1;
+}
+
/*
* Logs when a binary push state changes.
* Logged by the installer via public api.
@@ -3182,8 +3224,14 @@ message BinaryPushStateChanged {
INSTALL_FAILURE = 6;
INSTALL_CANCELLED = 7;
INSTALLER_ROLLBACK_REQUESTED = 8;
+ INSTALLER_ROLLBACK_SUCCESS = 9;
+ INSTALLER_ROLLBACK_FAILURE = 10;
}
optional State state = 6;
+ // Possible experiment ids for monitoring this push.
+ optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES];
+ // user id
+ optional int32 user_id = 8;
}
/** Represents USB port overheat event. */
@@ -3217,6 +3265,28 @@ message BatteryCycleCount {
optional int32 cycle_count = 1;
}
+/**
+ * Logs that an SD card is mounted and information about it, its type (public or private) and the
+ * size in bytes.
+ * Pulled from:
+ * StatsCompanionService
+ */
+
+message SDCardInfo {
+
+ enum Type {
+ UNKNOWN = 0;
+ TYPE_PUBLIC = 1;
+ TYPE_PRIVATE = 2;
+ OTHERS = 3;
+ }
+
+ // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+ optional Type type = 1;
+ // Total size of the sd card in bytes.
+ optional int64 size_bytes = 2;
+}
+
/*
* Logs when a connection becomes available and lost.
* Logged in StatsCompanionService.java
@@ -3269,6 +3339,33 @@ message ServiceLaunchReported {
optional string service_name = 3;
}
+/**
+ * Logs when a hidden API is used.
+ *
+ * Logged from:
+ * libcore/libart/src/main/java/dalvik/system/VMRuntime.java
+ */
+message HiddenApiUsed {
+ // The uid of the app making the hidden access.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Signature of the method or field accessed.
+ optional string signature = 2;
+
+ enum AccessMethod {
+ NONE = 0;
+ REFLECTION = 1;
+ JNI = 2;
+ LINKING = 3;
+ }
+
+ // Type of access.
+ optional AccessMethod access_method = 3;
+
+ // Whether the access was prevented or not.
+ optional bool access_denied = 4;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -4752,6 +4849,12 @@ message AppCompacted {
// The process state at the time of compaction.
optional android.app.ProcessStateEnum process_state = 16 [default = PROCESS_STATE_UNKNOWN];
+
+ // Free ZRAM in kilobytes before compaction.
+ optional int64 before_zram_free_kilobytes = 17;
+
+ // Free ZRAM in kilobytes after compaction.
+ optional int64 after_zram_free_kilobytes = 18;
}
/**
@@ -5511,13 +5614,6 @@ message DeviceIdentifierAccessDenied {
}
/**
- * Potential experiment ids that goes with a train install.
- */
-message TrainExperimentIds {
- repeated int64 experiment_id = 1;
-}
-
-/**
* Pulls the ongoing mainline install train version code.
* Pulled from StatsCompanionService
*/
@@ -5558,3 +5654,11 @@ message AssistGestureProgressReported {
// [0,100] progress for the assist gesture.
optional int32 progress = 1;
}
+
+/*
+ * Information about the time zone data on a device.
+ */
+message TimeZoneDataInfo {
+ // A version identifier for the data set on device. e.g. "2018i"
+ optional string tzdb_version = 1;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ed72b2914a34..1513834b6724 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -29,10 +29,11 @@
#include "../statscompanion_util.h"
#include "PowerStatsPuller.h"
#include "ResourceHealthManagerPuller.h"
-#include "StatsCompanionServicePuller.h"
#include "StatsCallbackPuller.h"
+#include "StatsCompanionServicePuller.h"
#include "StatsPullerManager.h"
#include "SubsystemSleepStatePuller.h"
+#include "TrainInfoPuller.h"
#include "statslog.h"
#include <iostream>
@@ -152,7 +153,7 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// temperature
{android::util::TEMPERATURE,
- {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
// binder_calls
{android::util::BINDER_CALLS,
{.additiveFields = {4, 5, 6, 8, 12},
@@ -231,6 +232,14 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// PermissionState.
{android::util::DANGEROUS_PERMISSION_STATE,
{.puller = new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE)}},
+ // TrainInfo.
+ {android::util::TRAIN_INFO, {.puller = new TrainInfoPuller()}},
+ // TimeZoneDataInfo.
+ {android::util::TIME_ZONE_DATA_INFO,
+ {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
+ // SDCardInfo
+ {android::util::SDCARD_INFO,
+ {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
new file mode 100644
index 000000000000..9d0924297912
--- /dev/null
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "external/StatsPuller.h"
+
+#include "TrainInfoPuller.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "statslog.h"
+#include "storage/StorageManager.h"
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TrainInfoPuller::TrainInfoPuller() :
+ StatsPuller(android::util::TRAIN_INFO) {
+}
+
+bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ InstallTrainInfo trainInfo;
+ bool ret = StorageManager::readTrainInfo(trainInfo);
+ if (!ret) {
+ ALOGW("Failed to read train info.");
+ return false;
+ }
+ auto event = make_shared<LogEvent>(getWallClockNs(), getElapsedRealtimeNs(), trainInfo);
+ data->push_back(event);
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/TrainInfoPuller.h b/cmds/statsd/src/external/TrainInfoPuller.h
new file mode 100644
index 000000000000..615d02351fd3
--- /dev/null
+++ b/cmds/statsd/src/external/TrainInfoPuller.h
@@ -0,0 +1,38 @@
+/*
+ * 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 "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads train info from disk.
+ */
+class TrainInfoPuller : public StatsPuller {
+ public:
+ TrainInfoPuller();
+
+ private:
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index b433c41518cc..d661ee8651be 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -478,6 +478,11 @@ void StatsdStats::noteBucketDropped(int64_t metricId) {
getAtomMetricStats(metricId).bucketDropped++;
}
+void StatsdStats::noteBucketUnknownCondition(int64_t metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).bucketUnknownCondition++;
+}
+
void StatsdStats::noteConditionChangeInNextBucket(int64_t metricId) {
lock_guard<std::mutex> lock(mLock);
getAtomMetricStats(metricId).conditionChangeInNextBucket++;
@@ -497,7 +502,7 @@ void StatsdStats::noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayN
std::min(pullStats.minBucketBoundaryDelayNs, timeDelayNs);
}
-StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int metricId) {
+StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int64_t metricId) {
auto atomMetricStatsIter = mAtomMetricStats.find(metricId);
if (atomMetricStatsIter != mAtomMetricStats.end()) {
return atomMetricStatsIter->second;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 5275c8f34fd0..e039be2b4395 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -409,6 +409,11 @@ public:
void noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs);
/**
+ * Number of buckets with unknown condition.
+ */
+ void noteBucketUnknownCondition(int64_t metricId);
+
+ /**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
* to collect stats after reset() has been called.
@@ -458,6 +463,7 @@ public:
long bucketDropped = 0;
int64_t minBucketBoundaryDelayNs = 0;
int64_t maxBucketBoundaryDelayNs = 0;
+ long bucketUnknownCondition = 0;
} AtomMetricStats;
private:
@@ -488,7 +494,7 @@ private:
std::map<int, PulledAtomStats> mPulledAtomStats;
// Maps metric ID to its stats. The size is capped by the number of metrics.
- std::map<int, AtomMetricStats> mAtomMetricStats;
+ std::map<int64_t, AtomMetricStats> mAtomMetricStats;
struct LogLossStats {
LogLossStats(int32_t sec, int32_t count, int32_t error)
@@ -532,7 +538,7 @@ private:
* Get a reference to AtomMetricStats for a metric. If none exists, create it. The reference
* will live as long as `this`.
*/
- StatsdStats::AtomMetricStats& getAtomMetricStats(int metricId);
+ StatsdStats::AtomMetricStats& getAtomMetricStats(int64_t metricId);
FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 40a4070d2974..dec36b54a1ce 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -20,6 +20,8 @@
#include "stats_log_util.h"
#include "statslog.h"
+#include <binder/IPCThreadState.h>
+
namespace android {
namespace os {
namespace statsd {
@@ -180,6 +182,25 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
}
}
+LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
+ bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
+ const std::vector<uint8_t>& experimentIds, int32_t userId) {
+ mLogdTimestampNs = getWallClockNs();
+ mElapsedTimestampNs = getElapsedRealtimeNs();
+ mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
+ mLogUid = android::IPCThreadState::self()->getCallingUid();
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
+}
+
LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const SpeakerImpedance& speakerImpedance) {
mLogdTimestampNs = wallClockTimestampNs;
@@ -340,6 +361,16 @@ LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
}
}
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const InstallTrainInfo& trainInfo) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::TRAIN_INFO;
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainInfo.experimentIds)));
+}
+
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 784376a1580c..111a619760df 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -55,6 +55,11 @@ struct AttributionNodeInternal {
int32_t mUid;
std::string mTag;
};
+
+struct InstallTrainInfo {
+ int64_t trainVersionCode;
+ std::vector<uint8_t> experimentIds;
+};
/**
* Wrapper for the log_msg structure.
*/
@@ -97,6 +102,11 @@ public:
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
+ // Constructs a BinaryPushStateChanged LogEvent from API call.
+ explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
+ bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
+ const std::vector<uint8_t>& experimentIds, int32_t userId);
+
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const SpeakerImpedance& speakerImpedance);
@@ -127,6 +137,9 @@ public:
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const VendorAtom& vendorAtom);
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const InstallTrainInfo& installTrainInfo);
+
~LogEvent();
/**
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 350745b2c326..e84f88d407d3 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -250,7 +250,7 @@ void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
}
bool CountMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
@@ -303,7 +303,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked(
if (prev != mCurrentFullCounters->end()) {
countWholeBucket += prev->second;
}
- tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
+ tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
countWholeBucket);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 6c1c47bbc093..da6b97cc4e59 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -433,7 +433,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondit
void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
flushIfNeededLocked(eventTime);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (auto& pair : whatIt.second) {
@@ -767,12 +767,13 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
!mSameConditionDimensionsInTracker,
!mHasLinksToAllConditionDimensionsInTracker,
&dimensionKeysInCondition);
- condition = (conditionState == ConditionState::kTrue);
+ condition = conditionState == ConditionState::kTrue;
if (mDimensionsInCondition.empty() && condition) {
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
} else {
- condition = mCondition;
+ // TODO: The unknown condition state is not handled here, we should fix it.
+ condition = mCondition == ConditionState::kTrue;
if (condition) {
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 1b830a3f69f5..ec561b527025 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -137,6 +137,7 @@ private:
FRIEND_TEST(DurationMetricTrackerTest, TestNoCondition);
FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedCondition);
+ FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState);
FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade);
FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket);
FRIEND_TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 7e695a69988f..3b4af6533e34 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -132,7 +132,7 @@ void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
}
void EventMetricProducer::onMatchedLogEventInternalLocked(
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d56a355f15d6..63017936b1db 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -320,15 +320,15 @@ void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
// When the metric wants to do random sampling and there is already one gauge atom for the
// current bucket, do not do it again.
case GaugeMetric::RANDOM_ONE_SAMPLE: {
- triggerPuller = mCondition && mCurrentSlicedBucket->empty();
+ triggerPuller = mCondition == ConditionState::kTrue && mCurrentSlicedBucket->empty();
break;
}
case GaugeMetric::CONDITION_CHANGE_TO_TRUE: {
- triggerPuller = mCondition;
+ triggerPuller = mCondition == ConditionState::kTrue;
break;
}
case GaugeMetric::FIRST_N_SAMPLES: {
- triggerPuller = mCondition;
+ triggerPuller = mCondition == ConditionState::kTrue;
break;
}
default:
@@ -364,7 +364,7 @@ void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTimeNs) {
VLOG("GaugeMetric %lld onConditionChanged", (long long)mMetricId);
flushIfNeededLocked(eventTimeNs);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
if (mIsPulled && mTriggerAtomId == -1) {
pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
@@ -377,7 +377,7 @@ void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
flushIfNeededLocked(eventTimeNs);
// If the condition is sliced, mCondition is true if any of the dimensions is true. And we will
// pull for every dimension.
- mCondition = overallCondition;
+ mCondition = overallCondition ? ConditionState::kTrue : ConditionState::kFalse;
if (mIsPulled && mTriggerAtomId == -1) {
pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
@@ -485,8 +485,8 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
gaugeVal = value.long_value;
}
for (auto& tracker : mAnomalyTrackers) {
- tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
- gaugeVal);
+ tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId,
+ eventKey, gaugeVal);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 11075685b7fa..4cf5333947d3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -45,7 +45,8 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
&dimensionKeysInCondition);
condition = (conditionState == ConditionState::kTrue);
} else {
- condition = mCondition;
+ // TODO: The unknown condition state is not handled here, we should fix it.
+ condition = mCondition == ConditionState::kTrue;
}
if (mDimensionsInCondition.empty() && condition) {
@@ -107,7 +108,8 @@ void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedT
if (it == mEventActivationMap.end()) {
return;
}
- if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT) {
+ if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT &&
+ it->second.state == ActivationState::kNotActive) {
it->second.state = ActivationState::kActiveOnBoot;
return;
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 849cb76ec392..8ab3b0680276 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -59,7 +59,7 @@ public:
mTimeBaseNs(timeBaseNs),
mCurrentBucketStartTimeNs(timeBaseNs),
mCurrentBucketNum(0),
- mCondition(conditionIndex >= 0 ? false : true),
+ mCondition(conditionIndex >= 0 ? ConditionState::kUnknown : ConditionState::kTrue),
mConditionSliced(false),
mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
@@ -315,7 +315,7 @@ protected:
int64_t mBucketSizeNs;
- bool mCondition;
+ ConditionState mCondition;
bool mConditionSliced;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 851ae9962d09..3cf378d7d7ce 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -154,7 +154,7 @@ ValueMetricProducer::ValueMetricProducer(
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
// Kicks off the puller immediately if condition is true and diff based.
- if (mIsPulled && mCondition && mUseDiff) {
+ if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
pullAndMatchEventsLocked(startTimeNs);
}
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
@@ -341,17 +341,21 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
flushIfNeededLocked(eventTimeNs);
// Pull on condition changes.
- if (mIsPulled && (mCondition != condition)) {
+ bool conditionChanged = mCondition != condition;
+ bool unknownToFalse = mCondition == ConditionState::kUnknown
+ && condition == ConditionState::kFalse;
+ // We do not need to pull when we go from unknown to false.
+ if (mIsPulled && conditionChanged && !unknownToFalse) {
pullAndMatchEventsLocked(eventTimeNs);
}
// when condition change from true to false, clear diff base but don't
// reset other counters as we may accumulate more value in the bucket.
- if (mUseDiff && mCondition && !condition) {
+ if (mUseDiff && mCondition == ConditionState::kTrue && condition == ConditionState::kFalse) {
resetBase();
}
- mCondition = condition;
+ mCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
}
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
@@ -372,7 +376,7 @@ int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTime
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
bool pullSuccess, int64_t originalPullTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mCondition) {
+ if (mCondition == ConditionState::kTrue) {
if (!pullSuccess) {
// If the pull failed, we won't be able to compute a diff.
invalidateCurrentBucket();
@@ -693,8 +697,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
wholeBucketVal += prev->second;
}
for (auto& tracker : mAnomalyTrackers) {
- tracker->detectAndDeclareAnomaly(
- eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
+ tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
+ wholeBucketVal);
}
}
}
@@ -725,6 +729,10 @@ void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
}
void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+ if (mCondition == ConditionState::kUnknown) {
+ StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
+ }
+
VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
(int)mCurrentSlicedBucket.size());
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index ccb1d4359e89..081e61ed21fa 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -155,8 +155,8 @@ protected:
const int64_t& currentBucketValue) {
for (auto& anomalyTracker : mAnomalyTrackers) {
if (anomalyTracker != nullptr) {
- anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mEventKey,
- currentBucketValue);
+ anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId,
+ mEventKey, currentBucketValue);
}
}
}
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 5cf012638dce..d4b57dd68134 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -73,6 +73,11 @@ UidMap::UidMap() : mBytesUsed(0) {}
UidMap::~UidMap() {}
+sp<UidMap> UidMap::getInstance() {
+ static sp<UidMap> sInstance = new UidMap();
+ return sInstance;
+}
+
bool UidMap::hasApp(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
@@ -336,6 +341,61 @@ size_t UidMap::getBytesUsed() const {
return mBytesUsed;
}
+void UidMap::writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings,
+ bool includeInstaller, const std::set<int32_t>& interestingUids,
+ std::set<string>* str_set, ProtoOutputStream* proto) {
+ lock_guard<mutex> lock(mMutex);
+
+ writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller, interestingUids,
+ str_set, proto);
+}
+
+void UidMap::writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
+ bool includeInstaller,
+ const std::set<int32_t>& interestingUids,
+ std::set<string>* str_set, ProtoOutputStream* proto) {
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
+ for (const auto& kv : mMap) {
+ if (!interestingUids.empty() &&
+ interestingUids.find(kv.first.first) == interestingUids.end()) {
+ continue;
+ }
+ uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+ if (str_set != nullptr) {
+ str_set->insert(kv.first.second);
+ proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
+ (long long)Hash64(kv.first.second));
+ if (includeVersionStrings) {
+ str_set->insert(kv.second.versionString);
+ proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH,
+ (long long)Hash64(kv.second.versionString));
+ }
+ if (includeInstaller) {
+ str_set->insert(kv.second.installer);
+ proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH,
+ (long long)Hash64(kv.second.installer));
+ }
+ } else {
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
+ if (includeVersionStrings) {
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING,
+ kv.second.versionString);
+ }
+ if (includeInstaller) {
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER,
+ kv.second.installer);
+ }
+ }
+
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
+ (long long)kv.second.versionCode);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
+ proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
+ proto->end(token);
+ }
+}
+
void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
bool includeVersionStrings, bool includeInstaller,
ProtoOutputStream* proto) {
@@ -381,43 +441,9 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::s
// Write snapshot from current uid map state.
uint64_t snapshotsToken =
proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
- for (const auto& kv : mMap) {
- uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
- FIELD_ID_SNAPSHOT_PACKAGE_INFO);
-
- if (str_set != nullptr) {
- str_set->insert(kv.first.second);
- proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
- (long long)Hash64(kv.first.second));
- if (includeVersionStrings) {
- str_set->insert(kv.second.versionString);
- proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH,
- (long long)Hash64(kv.second.versionString));
- }
- if (includeInstaller) {
- str_set->insert(kv.second.installer);
- proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH,
- (long long)Hash64(kv.second.installer));
- }
- } else {
- proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
- if (includeVersionStrings) {
- proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING,
- kv.second.versionString);
- }
- if (includeInstaller) {
- proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER,
- kv.second.installer);
- }
- }
-
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
- (long long)kv.second.versionCode);
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
- proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
- proto->end(token);
- }
+ writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller,
+ std::set<int32_t>() /*empty uid set means including every uid*/,
+ str_set, proto);
proto->end(snapshotsToken);
int64_t prevMin = getMinimumTimestampNs();
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 75ff507ef09a..a7c5fb27375c 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -91,6 +91,8 @@ public:
UidMap();
~UidMap();
static const std::map<std::string, uint32_t> sAidToUidMapping;
+
+ static sp<UidMap> getInstance();
/*
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
@@ -152,12 +154,25 @@ public:
std::set<int32_t> getAppUid(const string& package) const;
+ // Write current PackageInfoSnapshot to ProtoOutputStream.
+ // interestingUids: If not empty, only write the package info for these uids. If empty, write
+ // package info for all uids.
+ // str_set: if not null, add new string to the set and write str_hash to proto
+ // if null, write string to proto.
+ void writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings, bool includeInstaller,
+ const std::set<int32_t>& interestingUids, std::set<string>* str_set,
+ ProtoOutputStream* proto);
+
private:
std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
string normalizeAppName(const string& appName) const;
void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
+ void writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
+ bool includeInstaller, const std::set<int32_t>& interestingUids,
+ std::set<string>* str_set, ProtoOutputStream* proto);
+
mutable mutex mMutex;
mutable mutex mIsolatedMutex;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index f7428a50b3da..623d8bc06e38 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -425,6 +425,7 @@ message StatsdStatsReport {
optional int64 bucket_dropped = 8;
optional int64 min_bucket_boundary_delay_ns = 9;
optional int64 max_bucket_boundary_delay_ns = 10;
+ optional int64 bucket_unknown_condition = 11;
}
repeated AtomMetricStats atom_metric_stats = 17;
@@ -456,3 +457,17 @@ message StatsdStatsReport {
}
repeated LogLossStats detected_log_loss = 16;
}
+
+message AlertTriggerDetails {
+ message MetricValue {
+ optional int64 metric_id = 1;
+ optional DimensionsValue dimension_in_what = 2;
+ optional DimensionsValue dimension_in_condition = 3;
+ optional int64 value = 4;
+ }
+ oneof value {
+ MetricValue trigger_metric = 1;
+ EventMetricData trigger_event = 2;
+ }
+ optional UidMapping.PackageInfoSnapshot package_info = 3;
+}
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 01043a2143f0..ca645e186614 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -84,6 +84,7 @@ const int FIELD_ID_INVALIDATED_BUCKET = 7;
const int FIELD_ID_BUCKET_DROPPED = 8;
const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9;
const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10;
+const int FIELD_ID_BUCKET_UNKNOWN_CONDITION = 11;
namespace {
@@ -489,11 +490,11 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
protoOutput->end(token);
}
-void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
util::ProtoOutputStream *protoOutput) {
uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
FIELD_COUNT_REPEATED);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (int32_t)pair.first);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (long long)pair.first);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
(long long)pair.second.hardDimensionLimitReached);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
@@ -512,6 +513,8 @@ void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricSt
(long long)pair.second.minBucketBoundaryDelayNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
(long long)pair.second.maxBucketBoundaryDelayNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_UNKNOWN_CONDITION,
+ (long long)pair.second.bucketUnknownCondition);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index dcea0e653e22..59d4865f8977 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -74,7 +74,7 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
util::ProtoOutputStream* protoOutput);
// Helper function to write AtomMetricStats to ProtoOutputStream
-void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
util::ProtoOutputStream *protoOutput);
template<class T>
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 90f641a34b85..165e57c73743 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -38,10 +38,13 @@ using std::map;
#define STATS_DATA_DIR "/data/misc/stats-data"
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+#define TRAIN_INFO_DIR "/data/misc/train-info"
// for ConfigMetricsReportList
const int FIELD_ID_REPORTS = 2;
+std::mutex StorageManager::sTrainInfoMutex;
+
using android::base::StringPrintf;
using std::unique_ptr;
@@ -92,6 +95,71 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte
close(fd);
}
+bool StorageManager::writeTrainInfo(int64_t trainVersionCode,
+ const std::vector<uint8_t>& experimentIds) {
+ std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+
+ deleteAllFiles(TRAIN_INFO_DIR);
+
+ string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode);
+
+ int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ VLOG("Attempt to access %s but failed", file_name.c_str());
+ return false;
+ }
+
+ size_t result = write(fd, experimentIds.data(), experimentIds.size());
+ if (result == experimentIds.size()) {
+ VLOG("Successfully wrote %s", file_name.c_str());
+ } else {
+ VLOG("Failed to write %s", file_name.c_str());
+ return false;
+ }
+
+ result = fchown(fd, AID_STATSD, AID_STATSD);
+ if (result) {
+ VLOG("Failed to chown %s to statsd", file_name.c_str());
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+
+bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) {
+ std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
+
+ if (dir == NULL) {
+ VLOG("Directory does not exist: %s", TRAIN_INFO_DIR);
+ return false;
+ }
+
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') {
+ continue;
+ }
+ trainInfo.trainVersionCode = StrToInt64(name);
+ string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name);
+ int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ string str;
+ if (android::base::ReadFdToString(fd, &str)) {
+ close(fd);
+ std::copy(str.begin(), str.end(), std::back_inserter(trainInfo.experimentIds));
+ VLOG("Read train info file successful: %s", fullPath.c_str());
+ return true;
+ }
+ }
+ close(fd);
+ }
+ return false;
+}
+
void StorageManager::deleteFile(const char* file) {
if (remove(file) != 0) {
VLOG("Attempt to delete %s but is not found", file);
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index dcf3bb607380..d6df8674e59b 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -29,6 +29,11 @@ namespace statsd {
using android::util::ProtoOutputStream;
+struct TrainInfo {
+ int64_t trainVersionCode;
+ std::vector<uint8_t> experimentIds;
+};
+
class StorageManager : public virtual RefBase {
public:
/**
@@ -37,6 +42,16 @@ public:
static void writeFile(const char* file, const void* buffer, int numBytes);
/**
+ * Writes train info.
+ */
+ static bool writeTrainInfo(int64_t trainVersionCode, const std::vector<uint8_t>& experimentIds);
+
+ /**
+ * Reads train info.
+ */
+ static bool readTrainInfo(InstallTrainInfo& trainInfo);
+
+ /**
* Reads the file content to the buffer.
*/
static bool readFileToString(const char* file, string* content);
@@ -109,6 +124,8 @@ private:
* Prints disk usage statistics about a directory related to statsd.
*/
static void printDirStats(int out, const char* path);
+
+ static std::mutex sTrainInfoMutex;
};
} // namespace statsd
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index 42cac0cc4122..0ed2d75802da 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -16,7 +16,10 @@
#define DEBUG false
#include "Log.h"
+#include "FieldValue.h"
#include "IncidentdReporter.h"
+#include "packages/UidMap.h"
+#include "stats_log_util.h"
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
@@ -43,8 +46,18 @@ const int FIELD_ID_CONFIG_KEY = 3;
const int FIELD_ID_CONFIG_KEY_UID = 1;
const int FIELD_ID_CONFIG_KEY_ID = 2;
+const int FIELD_ID_TRIGGER_DETAILS = 4;
+const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
+const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
+const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
+const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3;
+const int FIELD_ID_METRIC_VALUE_VALUE = 4;
+
+const int FIELD_ID_PACKAGE_INFO = 3;
+
namespace {
-void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uint8_t>* protoData) {
+void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
+ int64_t metricValue, const ConfigKey& configKey, vector<uint8_t>* protoData) {
ProtoOutputStream headerProto;
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
uint64_t token =
@@ -53,6 +66,58 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
headerProto.end(token);
+ token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS);
+
+ // MetricValue trigger_metric = 1;
+ uint64_t metricToken =
+ headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC);
+ // message MetricValue {
+ // optional int64 metric_id = 1;
+ headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId);
+ // optional DimensionsValue dimension_in_what = 2;
+ uint64_t dimToken =
+ headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
+ headerProto.end(dimToken);
+
+ // optional DimensionsValue dimension_in_condition = 3;
+ dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto);
+ headerProto.end(dimToken);
+
+ // optional int64 value = 4;
+ headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
+
+ // }
+ headerProto.end(metricToken);
+
+ // write relevant uid package info
+ std::set<int32_t> uids;
+
+ for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
+ int uid = getUidIfExists(dim);
+ // any uid <= 2000 are predefined AID_*
+ if (uid > 2000) {
+ uids.insert(uid);
+ }
+ }
+
+ for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) {
+ int uid = getUidIfExists(dim);
+ if (uid > 2000) {
+ uids.insert(uid);
+ }
+ }
+
+ if (!uids.empty()) {
+ uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
+ UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
+ nullptr /*string set*/, &headerProto);
+ headerProto.end(token);
+ }
+
+ headerProto.end(token);
+
protoData->resize(headerProto.size());
size_t pos = 0;
auto iter = headerProto.data();
@@ -65,7 +130,8 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin
}
} // namespace
-bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
+bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
+ const MetricDimensionKey& dimensionKey, int64_t metricValue,
const ConfigKey& configKey) {
if (config.section_size() == 0) {
VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
@@ -76,7 +142,7 @@ bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_
IncidentReportArgs incidentReport;
vector<uint8_t> protoData;
- getProtoData(rule_id, configKey, &protoData);
+ getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey, &protoData);
incidentReport.addHeader(protoData);
for (int i = 0; i < config.section_size(); i++) {
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
index 1b83fe23de8f..e78a4d98dcd8 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.h
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.h
@@ -16,6 +16,7 @@
#pragma once
+#include "HashableDimensionKey.h"
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert, IncidentdDetails
@@ -26,7 +27,8 @@ namespace statsd {
/**
* Calls incidentd to trigger an incident report and put in dropbox for uploading.
*/
-bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
+bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
+ const MetricDimensionKey& dimensionKey, int64_t metricValue,
const ConfigKey& configKey);
} // namespace statsd
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index e0cbd5d25716..a98ecd586b42 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -27,3 +27,4 @@ on post-fs-data
mkdir /data/misc/stats-data/ 0770 statsd system
mkdir /data/misc/stats-service/ 0770 statsd system
mkdir /data/misc/stats-active-metric/ 0770 statsd system
+ mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 5f3aae3ab93a..4579ca6008ef 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -297,7 +297,8 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
// Setup a simple config, no activation
StatsdConfig config1;
- config1.set_id(12341);
+ int64_t cfgId1 = 12341;
+ config1.set_id(cfgId1);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
*config1.add_atom_matcher() = wakelockAcquireMatcher;
@@ -314,14 +315,12 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
countMetric2->set_what(wakelockAcquireMatcher.id());
countMetric2->set_bucket(FIVE_MINUTES);
- ConfigKey cfgKey1(uid, 12341);
- long timeBase1 = 1;
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+ ConfigKey cfgKey1(uid, cfgId1);
// Add another config, with two metrics, one with activation
StatsdConfig config2;
- config2.set_id(12342);
+ int64_t cfgId2 = 12342;
+ config2.set_id(cfgId2);
config2.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
*config2.add_atom_matcher() = wakelockAcquireMatcher;
@@ -344,11 +343,12 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric3ActivationTrigger->set_ttl_seconds(100);
- ConfigKey cfgKey2(uid, 12342);
+ ConfigKey cfgKey2(uid, cfgId2);
// Add another config, with two metrics, both with activations
StatsdConfig config3;
- config3.set_id(12342);
+ int64_t cfgId3 = 12343;
+ config3.set_id(cfgId3);
config3.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
*config3.add_atom_matcher() = wakelockAcquireMatcher;
@@ -376,14 +376,37 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric6ActivationTrigger->set_ttl_seconds(200);
- ConfigKey cfgKey3(uid, 12343);
+ ConfigKey cfgKey3(uid, cfgId3);
- processor->OnConfigUpdated(2, cfgKey2, config2);
- processor->OnConfigUpdated(3, cfgKey3, config3);
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
- EXPECT_EQ(3, processor->mMetricsManagers.size());
- auto it = processor->mMetricsManagers.find(cfgKey1);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
+ timeBase1, [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
+ activeConfigs.begin(), activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(1, cfgKey1, config1);
+ processor.OnConfigUpdated(2, cfgKey2, config2);
+ processor.OnConfigUpdated(3, cfgKey3, config3);
+
+ EXPECT_EQ(3, processor.mMetricsManagers.size());
+
+ // Expect the first config and both metrics in it to be active.
+ auto it = processor.mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
@@ -407,8 +430,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer2 = *metricIt;
EXPECT_TRUE(metricProducer2->isActive());
- it = processor->mMetricsManagers.find(cfgKey2);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ // Expect config 2 to be active. Metric 3 shouldn't be active, metric 4 should be active.
+ it = processor.mMetricsManagers.find(cfgKey2);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
@@ -432,8 +456,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer4 = *metricIt;
EXPECT_TRUE(metricProducer4->isActive());
- it = processor->mMetricsManagers.find(cfgKey3);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ // Expect the third config and both metrics in it to be inactive.
+ it = processor.mMetricsManagers.find(cfgKey3);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager3 = it->second;
EXPECT_FALSE(metricsManager3->isActive());
@@ -457,10 +482,30 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer6 = *metricIt;
EXPECT_FALSE(metricProducer6->isActive());
+ // No broadcast for active configs should have happened yet.
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activate all 3 metrics that were not active.
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ // Assert that all 3 configs are active.
+ EXPECT_TRUE(metricsManager1->isActive());
+ EXPECT_TRUE(metricsManager2->isActive());
+ EXPECT_TRUE(metricsManager3->isActive());
+
+ // A broadcast should have happened, and all 3 configs should be active in the broadcast.
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 3);
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1)
+ != activeConfigsBroadcast.end());
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2)
+ != activeConfigsBroadcast.end());
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId3)
+ != activeConfigsBroadcast.end());
+
+ // When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns.
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
EXPECT_TRUE(metricProducer3->isActive());
int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime);
@@ -472,8 +517,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime);
EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6);
- processor->WriteMetricsActivationToDisk(timeBase1 + 100 * NS_PER_SEC);
+ processor.WriteMetricsActivationToDisk(shutDownTime);
+ // Create a second StatsLogProcessor and push the same 3 configs.
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
@@ -481,6 +527,8 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
EXPECT_EQ(3, processor2->mMetricsManagers.size());
+
+ // First config and both metrics are active.
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1001 = it->second;
@@ -506,6 +554,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1002 = *metricIt;
EXPECT_TRUE(metricProducer1002->isActive());
+ // Second config is active. Metric 3 is inactive, metric 4 is active.
it = processor2->mMetricsManagers.find(cfgKey2);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1002 = it->second;
@@ -531,6 +580,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1004 = *metricIt;
EXPECT_TRUE(metricProducer1004->isActive());
+ // Config 3 is inactive. both metrics are inactive.
it = processor2->mMetricsManagers.find(cfgKey3);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1003 = it->second;
@@ -557,6 +607,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1006 = *metricIt;
EXPECT_FALSE(metricProducer1006->isActive());
+ // Assert that all 3 metrics with activation are inactive and that the ttls were properly set.
EXPECT_FALSE(metricProducer1003->isActive());
const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1003.ttl_ns);
@@ -572,12 +623,16 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
processor2->LoadMetricsActivationFromDisk();
+ // After loading activations from disk, assert that all 3 metrics are active.
EXPECT_TRUE(metricProducer1003->isActive());
EXPECT_EQ(timeBase2 + ttl3 - activation1003.ttl_ns, activation1003.activation_ns);
EXPECT_TRUE(metricProducer1005->isActive());
EXPECT_EQ(timeBase2 + ttl5 - activation1005.ttl_ns, activation1005.activation_ns);
EXPECT_TRUE(metricProducer1006->isActive());
EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns);
+
+ // Make sure no more broadcasts have happened.
+ EXPECT_EQ(broadcastCount, 1);
}
TEST(StatsLogProcessorTest, TestActivationOnBoot) {
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 960fbdab1c15..c10703c36b98 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -90,7 +90,8 @@ void detectAndDeclareAnomalies(AnomalyTracker& tracker,
const std::shared_ptr<DimToValMap>& bucket,
const int64_t& eventTimestamp) {
for (const auto& kv : *bucket) {
- tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second);
+ tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, 0 /*metric_id*/, kv.first,
+ kv.second);
}
}
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 29e86f3f9456..85d8a5613a8b 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -66,17 +66,42 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
auto config = CreateStatsdConfig();
int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- sp<MetricProducer> metricProducer =
- processor->mMetricsManagers.begin()->second->mAllMetricProducers[0];
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
+ bucketStartTimeNs, [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
+ activeConfigs.begin(), activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
@@ -93,13 +118,19 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
std::unique_ptr<LogEvent> event;
event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
// Activated by battery save mode.
event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -109,12 +140,13 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// First processed event.
event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
// Activated by screen on event.
event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
bucketStartTimeNs + 20);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
@@ -126,7 +158,8 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// 2nd processed event.
// The activation by screen_on event expires, but the one by battery save mode is still active.
event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
@@ -134,15 +167,21 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
// 3rd processed event.
event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
// All activations expired.
event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -153,8 +192,12 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// Re-activate.
event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -163,11 +206,11 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index b54096441d3f..b294cad1802c 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -117,6 +117,7 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -140,6 +141,51 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
EXPECT_EQ(1LL, buckets2[0].mDuration);
}
+TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
+ event3.init();
+ LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
+ event4.init();
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
/**
* The duration starts from the first bucket, through the two partial buckets (10-70sec),
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 572b1991f426..7e7ffeda8053 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2176,7 +2176,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
vector<shared_ptr<LogEvent>> allData;
valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
@@ -2226,7 +2226,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
// Max delay is set to 0 so pull will exceed max delay.
valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2257,7 +2257,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
// Pull should not be called.
@@ -2299,7 +2299,7 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
valueProducer.mHasGlobalBase = false;
valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2351,7 +2351,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2429,7 +2429,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2);
EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid);
EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
@@ -2481,7 +2481,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2564,7 +2564,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
new file mode 100644
index 000000000000..f66de0518f80
--- /dev/null
+++ b/cmds/statsd/tests/storage/StorageManager_test.cpp
@@ -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.
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include "src/storage/StorageManager.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using testing::Contains;
+
+TEST(StorageManagerTest, TrainInfoReadWriteTest) {
+ InstallTrainInfo trainInfo;
+ trainInfo.trainVersionCode = 12345;
+ const char* expIds = "test_ids";
+ trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
+
+ StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.experimentIds);
+
+ InstallTrainInfo result;
+ StorageManager::readTrainInfo(result);
+ EXPECT_EQ(trainInfo.trainVersionCode, result.trainVersionCode);
+ EXPECT_EQ(trainInfo.experimentIds.size(), result.experimentIds.size());
+ EXPECT_EQ(trainInfo.experimentIds, result.experimentIds);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index d29e68e5a187..3180b77f5700 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -26,6 +26,8 @@ import android.os.SystemClock;
import android.os.SystemProperties;
public class PowerCommand extends Svc.Command {
+ private static final int FORCE_SUSPEND_DELAY_DEFAULT_MILLIS = 0;
+
public PowerCommand() {
super("power");
}
@@ -42,7 +44,17 @@ public class PowerCommand extends Svc.Command {
+ " svc power reboot [reason]\n"
+ " Perform a runtime shutdown and reboot device with specified reason.\n"
+ " svc power shutdown\n"
- + " Perform a runtime shutdown and power off the device.\n";
+ + " Perform a runtime shutdown and power off the device.\n"
+ + " svc power forcesuspend [t]\n"
+ + " Force the system into suspend, ignoring all wakelocks.\n"
+ + " t - Number of milliseconds to wait before issuing force-suspend.\n"
+ + " Helps with devices that can't suspend while plugged in.\n"
+ + " Defaults to " + FORCE_SUSPEND_DELAY_DEFAULT_MILLIS + ".\n"
+ + " When using a delay, you must use the nohup shell modifier:\n"
+ + " 'adb shell nohup svc power forcesuspend [time]'\n"
+ + " Use caution; this is dangerous. It puts the device to sleep\n"
+ + " immediately without giving apps or the system an opportunity to\n"
+ + " save their state.\n";
}
public void run(String[] args) {
@@ -101,6 +113,20 @@ public class PowerCommand extends Svc.Command {
maybeLogRemoteException("Failed to shutdown.");
}
return;
+ } else if ("forcesuspend".equals(args[1])) {
+ int delayMillis = args.length > 2
+ ? Integer.parseInt(args[2]) : FORCE_SUSPEND_DELAY_DEFAULT_MILLIS;
+ try {
+ Thread.sleep(delayMillis);
+ if (!pm.forceSuspend()) {
+ System.err.println("Failed to force suspend.");
+ }
+ } catch (InterruptedException e) {
+ System.err.println("Failed to force suspend: " + e);
+ } catch (RemoteException e) {
+ maybeLogRemoteException("Failed to force-suspend with exception: " + e);
+ }
+ return;
}
}
}