summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp10
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java77
-rw-r--r--cmds/incidentd/src/FdBuffer.cpp22
-rw-r--r--cmds/incidentd/src/FdBuffer.h2
-rw-r--r--cmds/incidentd/src/PrivacyFilter.cpp20
-rw-r--r--cmds/incidentd/src/Reporter.cpp2
-rw-r--r--cmds/incidentd/src/Section.cpp115
-rw-r--r--cmds/incidentd/src/incidentd_util.cpp29
-rw-r--r--cmds/incidentd/src/incidentd_util.h30
-rw-r--r--cmds/statsd/src/atoms.proto5
-rw-r--r--cmds/statsd/tests/FieldValue_test.cpp329
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp1338
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp2824
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp51
-rw-r--r--cmds/statsd/tests/shell/ShellSubscriber_test.cpp27
-rw-r--r--cmds/statsd/tests/state/StateTracker_test.cpp755
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp127
-rw-r--r--cmds/statsd/tests/statsd_test_util.h26
-rw-r--r--core/java/android/app/INotificationManager.aidl6
-rw-r--r--core/java/android/app/NotificationManager.java4
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java2
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java79
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java79
-rw-r--r--core/java/android/os/PowerManager.java18
-rw-r--r--core/java/android/view/InsetsController.java30
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java36
-rw-r--r--core/java/android/widget/Toast.java3
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java27
-rw-r--r--docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.pngbin0 -> 28504 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.pngbin0 -> 25510 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.pngbin0 -> 25561 bytes
-rw-r--r--libs/protoutil/include/android/util/ProtoOutputStream.h1
-rw-r--r--libs/protoutil/src/EncodedBuffer.cpp14
-rw-r--r--libs/protoutil/src/ProtoOutputStream.cpp8
-rw-r--r--media/java/android/media/AudioManager.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_activity.xml1
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_view.xml41
-rw-r--r--packages/SystemUI/res/layout/controls_no_favorites.xml1
-rw-r--r--packages/SystemUI/res/layout/keyguard_media_header.xml4
-rw-r--r--packages/SystemUI/res/layout/qs_media_panel.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml17
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java9
-rw-r--r--services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java26
-rw-r--r--services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java30
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java2
-rw-r--r--services/core/java/com/android/server/PinnerService.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java1
-rw-r--r--services/core/java/com/android/server/notification/BubbleExtractor.java41
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java46
-rw-r--r--services/core/java/com/android/server/notification/ShortcutHelper.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java95
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/Task.java16
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java8
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java235
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java52
-rw-r--r--tests/BootImageProfileTest/AndroidTest.xml4
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java91
-rw-r--r--wifi/tests/AndroidTest.xml4
81 files changed, 3853 insertions, 3336 deletions
diff --git a/Android.bp b/Android.bp
index 3f06ffd7ecd8..b0e0b35a1f76 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1133,16 +1133,6 @@ aidl_mapping {
output: "framework-aidl-mappings.txt",
}
-genrule {
- name: "framework-annotation-proc-index",
- srcs: [":framework-annotation-proc"],
- cmd: "unzip -qp $(in) unsupportedappusage/unsupportedappusage_index.csv > $(out)",
- out: ["unsupportedappusage_index.csv"],
- dist: {
- targets: ["droidcore"],
- },
-}
-
// Avoid including Parcelable classes as we don't want to have two copies of
// Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
// and TeleService app (packages/services/Telephony).
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 02c55b7c8df9..5f86ed621084 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -52,6 +52,7 @@ import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.ParsableByteArray;
+import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.ColorInfo;
import java.io.EOFException;
@@ -60,6 +61,7 @@ import java.io.InterruptedIOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -688,12 +690,83 @@ public final class MediaParser {
* Returns an immutable list with the names of the parsers that are suitable for container
* formats with the given {@link MediaFormat}.
*
- * <p>TODO: List which properties are taken into account. E.g. MimeType.
+ * <p>A parser supports a {@link MediaFormat} if the mime type associated with {@link
+ * MediaFormat#KEY_MIME} corresponds to the supported container format.
+ *
+ * @param mediaFormat The {@link MediaFormat} to check support for.
+ * @return The parser names that support the given {@code mediaFormat}, or the list of all
+ * parsers available if no container specific format information is provided.
*/
@NonNull
@ParserName
public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
- throw new UnsupportedOperationException();
+ String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
+ mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim());
+ if (TextUtils.isEmpty(mimeType)) {
+ // No MIME type provided. Return all.
+ return Collections.unmodifiableList(
+ new ArrayList<>(EXTRACTOR_FACTORIES_BY_NAME.keySet()));
+ }
+ ArrayList<String> result = new ArrayList<>();
+ switch (mimeType) {
+ case "video/x-matroska":
+ case "audio/x-matroska":
+ case "video/x-webm":
+ case "audio/x-webm":
+ result.add(PARSER_NAME_MATROSKA);
+ break;
+ case "video/mp4":
+ case "audio/mp4":
+ case "application/mp4":
+ result.add(PARSER_NAME_MP4);
+ result.add(PARSER_NAME_FMP4);
+ break;
+ case "audio/mpeg":
+ result.add(PARSER_NAME_MP3);
+ break;
+ case "audio/aac":
+ result.add(PARSER_NAME_ADTS);
+ break;
+ case "audio/ac3":
+ result.add(PARSER_NAME_AC3);
+ break;
+ case "video/mp2t":
+ case "audio/mp2t":
+ result.add(PARSER_NAME_TS);
+ break;
+ case "video/x-flv":
+ result.add(PARSER_NAME_FLV);
+ break;
+ case "video/ogg":
+ case "audio/ogg":
+ case "application/ogg":
+ result.add(PARSER_NAME_OGG);
+ break;
+ case "video/mp2p":
+ case "video/mp1s":
+ result.add(PARSER_NAME_PS);
+ break;
+ case "audio/vnd.wave":
+ case "audio/wav":
+ case "audio/wave":
+ case "audio/x-wav":
+ result.add(PARSER_NAME_WAV);
+ break;
+ case "audio/amr":
+ result.add(PARSER_NAME_AMR);
+ break;
+ case "audio/ac4":
+ result.add(PARSER_NAME_AC4);
+ break;
+ case "audio/flac":
+ case "audio/x-flac":
+ result.add(PARSER_NAME_FLAC);
+ break;
+ default:
+ // No parsers support the given mime type. Do nothing.
+ break;
+ }
+ return Collections.unmodifiableList(result);
}
// Private fields.
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index d295b84baf67..78c322edcccc 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -17,6 +17,7 @@
#include "Log.h"
#include "FdBuffer.h"
+#include "incidentd_util.h"
#include <log/log.h>
#include <utils/SystemClock.h>
@@ -31,17 +32,24 @@ namespace os {
namespace incidentd {
const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 6144; // 96 MB max
+const ssize_t MAX_BUFFER_SIZE = 96 * 1024 * 1024; // 96 MB
-FdBuffer::FdBuffer()
- :mBuffer(new EncodedBuffer(BUFFER_SIZE)),
+FdBuffer::FdBuffer(): FdBuffer(get_buffer_from_pool(), /* isBufferPooled= */ true) {
+}
+
+FdBuffer::FdBuffer(sp<EncodedBuffer> buffer, bool isBufferPooled)
+ :mBuffer(buffer),
mStartTime(-1),
mFinishTime(-1),
mTimedOut(false),
- mTruncated(false) {
+ mTruncated(false),
+ mIsBufferPooled(isBufferPooled) {
}
FdBuffer::~FdBuffer() {
+ if (mIsBufferPooled) {
+ return_buffer_to_pool(mBuffer);
+ }
}
status_t FdBuffer::read(int fd, int64_t timeout) {
@@ -51,7 +59,7 @@ status_t FdBuffer::read(int fd, int64_t timeout) {
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
while (true) {
- if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ if (mBuffer->size() >= MAX_BUFFER_SIZE) {
mTruncated = true;
VLOG("Truncating data");
break;
@@ -106,7 +114,7 @@ status_t FdBuffer::readFully(int fd) {
mStartTime = uptimeMillis();
while (true) {
- if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ if (mBuffer->size() >= MAX_BUFFER_SIZE) {
// Don't let it get too big.
mTruncated = true;
VLOG("Truncating data");
@@ -156,7 +164,7 @@ status_t FdBuffer::readProcessedDataInStream(int fd, unique_fd toFd, unique_fd f
// This is the buffer used to store processed data
while (true) {
- if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ if (mBuffer->size() >= MAX_BUFFER_SIZE) {
VLOG("Truncating data");
mTruncated = true;
break;
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index a3493604f425..9b2794d165fb 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -35,6 +35,7 @@ using namespace android::util;
class FdBuffer {
public:
FdBuffer();
+ FdBuffer(sp<EncodedBuffer> buffer, bool isBufferPooled = false);
~FdBuffer();
/**
@@ -114,6 +115,7 @@ private:
int64_t mFinishTime;
bool mTimedOut;
bool mTruncated;
+ bool mIsBufferPooled;
};
} // namespace incidentd
diff --git a/cmds/incidentd/src/PrivacyFilter.cpp b/cmds/incidentd/src/PrivacyFilter.cpp
index d00ecdde5c63..0d427d1021a6 100644
--- a/cmds/incidentd/src/PrivacyFilter.cpp
+++ b/cmds/incidentd/src/PrivacyFilter.cpp
@@ -19,9 +19,6 @@
#include "incidentd_util.h"
#include "PrivacyFilter.h"
#include "proto_util.h"
-
-#include "incidentd_util.h"
-#include "proto_util.h"
#include "Section.h"
#include <android-base/file.h>
@@ -129,6 +126,8 @@ public:
FieldStripper(const Privacy* restrictions, const sp<ProtoReader>& data,
uint8_t bufferLevel);
+ ~FieldStripper();
+
/**
* Take the data that we have, and filter it down so that no fields
* are more sensitive than the given privacy policy.
@@ -167,6 +166,7 @@ private:
*/
uint8_t mCurrentLevel;
+ sp<EncodedBuffer> mEncodedBuffer;
};
FieldStripper::FieldStripper(const Privacy* restrictions, const sp<ProtoReader>& data,
@@ -174,19 +174,25 @@ FieldStripper::FieldStripper(const Privacy* restrictions, const sp<ProtoReader>&
:mRestrictions(restrictions),
mData(data),
mSize(data->size()),
- mCurrentLevel(bufferLevel) {
+ mCurrentLevel(bufferLevel),
+ mEncodedBuffer(get_buffer_from_pool()) {
if (mSize < 0) {
ALOGW("FieldStripper constructed with a ProtoReader that doesn't support size."
" Data will be missing.");
}
}
+FieldStripper::~FieldStripper() {
+ return_buffer_to_pool(mEncodedBuffer);
+}
+
status_t FieldStripper::strip(const uint8_t privacyPolicy) {
// If the current strip level is less (fewer fields retained) than what's already in the
// buffer, then we can skip it.
if (mCurrentLevel < privacyPolicy) {
PrivacySpec spec(privacyPolicy);
- ProtoOutputStream proto;
+ mEncodedBuffer->clear();
+ ProtoOutputStream proto(mEncodedBuffer);
// Optimization when no strip happens.
if (mRestrictions == NULL || spec.RequireAll()) {
@@ -267,7 +273,7 @@ status_t PrivacyFilter::writeData(const FdBuffer& buffer, uint8_t bufferLevel,
// Order the writes by privacy filter, with increasing levels of filtration,k
// so we can do the filter once, and then write many times.
sort(mOutputs.begin(), mOutputs.end(),
- [](const sp<FilterFd>& a, const sp<FilterFd>& b) -> bool {
+ [](const sp<FilterFd>& a, const sp<FilterFd>& b) -> bool {
return a->getPrivacyPolicy() < b->getPrivacyPolicy();
});
@@ -370,7 +376,7 @@ status_t filter_and_write_report(int to, int from, uint8_t bufferLevel,
write_field_or_skip(NULL, reader, fieldTag, true);
}
}
-
+ clear_buffer_pool();
err = reader->getError();
if (err != NO_ERROR) {
ALOGW("filter_and_write_report reader had an error: %s", strerror(-err));
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index ad253422452e..86a78f095f52 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -698,7 +698,7 @@ DONE:
listener->onReportFailed();
});
}
-
+ clear_buffer_pool();
ALOGI("Done taking incident report err=%s", strerror(-err));
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index c703c3ce0951..dec9cb0ad4ff 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -36,6 +36,7 @@
#include <log/log_read.h>
#include <log/logprint.h>
#include <private/android_logger.h>
+#include <sys/mman.h>
#include "FdBuffer.h"
#include "Privacy.h"
@@ -106,7 +107,6 @@ status_t FileSection::Execute(ReportWriter* writer) const {
return NO_ERROR;
}
- FdBuffer buffer;
Fpipe p2cPipe;
Fpipe c2pPipe;
// initiate pipes to pass data to/from incident_helper
@@ -122,6 +122,7 @@ status_t FileSection::Execute(ReportWriter* writer) const {
}
// parent process
+ FdBuffer buffer;
status_t readStatus = buffer.readProcessedDataInStream(fd.get(), std::move(p2cPipe.writeFd()),
std::move(c2pPipe.readFd()),
this->timeoutMs, mIsSysfs);
@@ -356,7 +357,6 @@ CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
CommandSection::~CommandSection() { free(mCommand); }
status_t CommandSection::Execute(ReportWriter* writer) const {
- FdBuffer buffer;
Fpipe cmdPipe;
Fpipe ihPipe;
@@ -377,6 +377,7 @@ status_t CommandSection::Execute(ReportWriter* writer) const {
}
cmdPipe.writeFd().reset();
+ FdBuffer buffer;
status_t readStatus = buffer.read(ihPipe.readFd().get(), this->timeoutMs);
writer->setSectionStats(buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
@@ -574,6 +575,16 @@ static inline int32_t get4LE(uint8_t const* src) {
}
status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
+ // heap profile shows that liblog malloc & free significant amount of memory in this process.
+ // Hence forking a new process to prevent memory fragmentation.
+ pid_t pid = fork();
+ if (pid < 0) {
+ ALOGW("[%s] failed to fork", this->name.string());
+ return errno;
+ }
+ if (pid > 0) {
+ return wait_child(pid, this->timeoutMs);
+ }
// Open log buffer and getting logs since last retrieved time if any.
unique_ptr<logger_list, void (*)(logger_list*)> loggers(
gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
@@ -583,31 +594,31 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
if (android_logger_open(loggers.get(), mLogID) == NULL) {
ALOGE("[%s] Can't get logger.", this->name.string());
- return -1;
+ _exit(EXIT_FAILURE);
}
log_msg msg;
log_time lastTimestamp(0);
ProtoOutputStream proto;
+ status_t err = OK;
while (true) { // keeps reading until logd buffer is fully read.
- status_t err = android_logger_list_read(loggers.get(), &msg);
- // err = 0 - no content, unexpected connection drop or EOF.
- // err = +ive number - size of retrieved data from logger
- // err = -ive number, OS supplied error _except_ for -EAGAIN
- // err = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end of data.
- if (err <= 0) {
- if (err != -EAGAIN) {
+ status_t status = android_logger_list_read(loggers.get(), &msg);
+ // status = 0 - no content, unexpected connection drop or EOF.
+ // status = +ive number - size of retrieved data from logger
+ // status = -ive number, OS supplied error _except_ for -EAGAIN
+ // status = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end.
+ if (status <= 0) {
+ if (status != -EAGAIN) {
ALOGW("[%s] fails to read a log_msg.\n", this->name.string());
+ err = -status;
}
- // dump previous logs and don't consider this error a failure.
break;
}
if (mBinary) {
// remove the first uint32 which is tag's index in event log tags
android_log_context context = create_android_log_parser(msg.msg() + sizeof(uint32_t),
msg.len() - sizeof(uint32_t));
- ;
android_log_list_element elem;
lastTimestamp.tv_sec = msg.entry.sec;
@@ -667,9 +678,10 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
}
} else {
AndroidLogEntry entry;
- err = android_log_processLogBuffer(&msg.entry, &entry);
- if (err != NO_ERROR) {
+ status = android_log_processLogBuffer(&msg.entry, &entry);
+ if (status != OK) {
ALOGW("[%s] fails to process to an entry.\n", this->name.string());
+ err = status;
break;
}
lastTimestamp.tv_sec = entry.tv_sec;
@@ -688,17 +700,24 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
trimTail(entry.message, entry.messageLen));
proto.end(token);
}
+ if (!proto.flush(pipeWriteFd.get())) {
+ if (errno == EPIPE) {
+ ALOGW("[%s] wrote to a broken pipe\n", this->name.string());
+ }
+ err = errno;
+ break;
+ }
+ proto.clear();
}
gLastLogsRetrieved[mLogID] = lastTimestamp;
- if (!proto.flush(pipeWriteFd.get()) && errno == EPIPE) {
- ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
- return EPIPE;
- }
- return NO_ERROR;
+ _exit(err);
}
// ================================================================================
+const int LINK_NAME_LEN = 64;
+const int EXE_NAME_LEN = 1024;
+
TombstoneSection::TombstoneSection(int id, const char* type, const int64_t timeoutMs)
: WorkerThreadSection(id, timeoutMs), mType(type) {
name = "tombstone ";
@@ -716,25 +735,37 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
const std::set<int> hal_pids = get_interesting_hal_pids();
- ProtoOutputStream proto;
+ auto pooledBuffer = get_buffer_from_pool();
+ ProtoOutputStream proto(pooledBuffer);
+ // dumpBufferSize should be a multiple of page size (4 KB) to reduce memory fragmentation
+ size_t dumpBufferSize = 64 * 1024; // 64 KB is enough for most tombstone dump
+ char* dumpBuffer = (char*)mmap(NULL, dumpBufferSize, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
struct dirent* d;
+ char link_name[LINK_NAME_LEN];
+ char exe_name[EXE_NAME_LEN];
status_t err = NO_ERROR;
while ((d = readdir(proc.get()))) {
int pid = atoi(d->d_name);
if (pid <= 0) {
continue;
}
-
- const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
- std::string exe;
- if (!android::base::Readlink(link_name, &exe)) {
- ALOGE("Section %s: Can't read '%s': %s\n", name.string(),
- link_name.c_str(), strerror(errno));
+ snprintf(link_name, LINK_NAME_LEN, "/proc/%d/exe", pid);
+ struct stat fileStat;
+ if (stat(link_name, &fileStat) != OK) {
continue;
}
+ size_t exe_name_len = readlink(link_name, exe_name, EXE_NAME_LEN);
+ if (exe_name_len < 0 || exe_name_len >= EXE_NAME_LEN) {
+ ALOGE("[%s] Can't read '%s': %s", name.string(), link_name, strerror(errno));
+ continue;
+ }
+ // readlink(2) does not put a null terminator at the end
+ exe_name[exe_name_len] = '\0';
bool is_java_process;
- if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+ if (strncmp(exe_name, "/system/bin/app_process32", LINK_NAME_LEN) == 0 ||
+ strncmp(exe_name, "/system/bin/app_process64", LINK_NAME_LEN) == 0) {
if (mType != "java") continue;
// Don't bother dumping backtraces for the zygote.
if (IsZygote(pid)) {
@@ -743,7 +774,7 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
}
is_java_process = true;
- } else if (should_dump_native_traces(exe.c_str())) {
+ } else if (should_dump_native_traces(exe_name)) {
if (mType != "native") continue;
is_java_process = false;
} else if (hal_pids.find(pid) != hal_pids.end()) {
@@ -799,29 +830,37 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
ALOGE("[%s] child had an issue: %s\n", this->name.string(), strerror(-cStatus));
}
- auto dump = std::make_unique<char[]>(buffer.size());
+ // Resize dump buffer
+ if (dumpBufferSize < buffer.size()) {
+ munmap(dumpBuffer, dumpBufferSize);
+ while(dumpBufferSize < buffer.size()) dumpBufferSize = dumpBufferSize << 1;
+ dumpBuffer = (char*)mmap(NULL, dumpBufferSize, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ }
sp<ProtoReader> reader = buffer.data()->read();
int i = 0;
while (reader->hasNext()) {
- dump[i] = reader->next();
+ dumpBuffer[i] = reader->next();
i++;
}
uint64_t token = proto.start(android::os::BackTraceProto::TRACES);
proto.write(android::os::BackTraceProto::Stack::PID, pid);
- proto.write(android::os::BackTraceProto::Stack::DUMP, dump.get(), i);
+ proto.write(android::os::BackTraceProto::Stack::DUMP, dumpBuffer, i);
proto.write(android::os::BackTraceProto::Stack::DUMP_DURATION_NS,
static_cast<long long>(Nanotime() - start));
proto.end(token);
dumpPipe.readFd().reset();
- }
-
- if (!proto.flush(pipeWriteFd.get()) && errno == EPIPE) {
- ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
- if (err != NO_ERROR) {
- return EPIPE;
+ if (!proto.flush(pipeWriteFd.get())) {
+ if (errno == EPIPE) {
+ ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+ }
+ err = errno;
+ break;
}
+ proto.clear();
}
-
+ munmap(dumpBuffer, dumpBufferSize);
+ return_buffer_to_pool(pooledBuffer);
return err;
}
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index 2649fb975792..150ab9991a2d 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -18,6 +18,7 @@
#include "incidentd_util.h"
+#include <android/util/EncodedBuffer.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <wait.h>
@@ -28,8 +29,6 @@ namespace android {
namespace os {
namespace incidentd {
-using namespace android::base;
-
const Privacy* get_privacy_of_section(int id) {
int l = 0;
int r = PRIVACY_POLICY_COUNT - 1;
@@ -48,6 +47,30 @@ const Privacy* get_privacy_of_section(int id) {
return NULL;
}
+std::vector<sp<EncodedBuffer>> gBufferPool;
+std::mutex gBufferPoolLock;
+
+sp<EncodedBuffer> get_buffer_from_pool() {
+ std::scoped_lock<std::mutex> lock(gBufferPoolLock);
+ if (gBufferPool.size() == 0) {
+ return new EncodedBuffer();
+ }
+ sp<EncodedBuffer> buffer = gBufferPool.back();
+ gBufferPool.pop_back();
+ return buffer;
+}
+
+void return_buffer_to_pool(sp<EncodedBuffer> buffer) {
+ buffer->clear();
+ std::scoped_lock<std::mutex> lock(gBufferPoolLock);
+ gBufferPool.push_back(buffer);
+}
+
+void clear_buffer_pool() {
+ std::scoped_lock<std::mutex> lock(gBufferPoolLock);
+ gBufferPool.clear();
+}
+
// ================================================================================
Fpipe::Fpipe() : mRead(), mWrite() {}
@@ -84,7 +107,7 @@ pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status) {
status = &dummy_status;
}
*status = 0;
- pid_t pid = fork();
+ pid_t pid = vfork();
if (pid < 0) {
*status = -errno;
return -1;
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index a54993fed42d..84998892e33c 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -19,18 +19,21 @@
#define INCIDENTD_UTIL_H
#include <stdarg.h>
-#include <unistd.h>
-
-#include <android-base/unique_fd.h>
#include <utils/Errors.h>
#include "Privacy.h"
namespace android {
+
+namespace util {
+class EncodedBuffer;
+}
+
namespace os {
namespace incidentd {
-using namespace android::base;
+using android::base::unique_fd;
+using android::util::EncodedBuffer;
/**
* Looks up Privacy of a section in the auto-gen PRIVACY_POLICY_LIST;
@@ -38,6 +41,25 @@ using namespace android::base;
const Privacy* get_privacy_of_section(int id);
/**
+ * Get an EncodedBuffer from an internal pool, or create and return a new one if the pool is empty.
+ * The EncodedBuffer should be returned after use.
+ * Thread safe.
+ */
+sp<EncodedBuffer> get_buffer_from_pool();
+
+/**
+ * Return the EncodedBuffer back to the pool for reuse.
+ * Thread safe.
+ */
+void return_buffer_to_pool(sp<EncodedBuffer> buffer);
+
+/**
+ * Clear the buffer pool to free memory, after taking an incident report.
+ * Thread safe.
+ */
+void clear_buffer_pool();
+
+/**
* This class wraps android::base::Pipe.
*/
class Fpipe {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5f2f546388a0..b3d534a4bce1 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -78,7 +78,8 @@ message Atom {
// Pushed atoms start at 2.
oneof pushed {
// For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
- BleScanStateChanged ble_scan_state_changed = 2 [(module) = "bluetooth"];
+ BleScanStateChanged ble_scan_state_changed = 2
+ [(module) = "bluetooth", (module) = "statsdtest"];
ProcessStateChanged process_state_changed = 3 [(module) = "framework"];
BleScanResultReceived ble_scan_result_received = 4 [(module) = "bluetooth"];
SensorStateChanged sensor_state_changed =
@@ -434,7 +435,7 @@ message Atom {
ProcessMemoryState process_memory_state = 10013 [(module) = "framework"];
SystemElapsedRealtime system_elapsed_realtime = 10014 [(module) = "framework"];
SystemUptime system_uptime = 10015 [(module) = "framework", (module) = "statsdtest"];
- CpuActiveTime cpu_active_time = 10016 [(module) = "framework"];
+ CpuActiveTime cpu_active_time = 10016 [(module) = "framework", (module) = "statsdtest"];
CpuClusterTime cpu_cluster_time = 10017 [(module) = "framework", (module) = "statsdtest"];
DiskSpace disk_space = 10018 [deprecated=true, (module) = "statsdtest"];
RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index a5ff0674f2dd..0bf24f1d3606 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -14,13 +14,16 @@
* limitations under the License.
*/
#include <gtest/gtest.h>
+
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "matchers/matcher_util.h"
#include "src/logd/LogEvent.h"
+#include "stats_event.h"
#include "stats_log_util.h"
#include "stats_util.h"
#include "subscriber/SubscriberReporter.h"
+#include "tests/statsd_test_util.h"
#ifdef __ANDROID__
@@ -30,6 +33,58 @@ namespace android {
namespace os {
namespace statsd {
+namespace {
+void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const vector<int>& attributionUids, const vector<string>& attributionTags,
+ const string& name) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const vector<int>& attributionUids, const vector<string>& attributionTags,
+ const int32_t value) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeInt32(statsEvent, value);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+} // anonymous namespace
+
TEST(AtomMatcherTest, TestFieldTranslation) {
FieldMatcher matcher1;
matcher1.set_field(10);
@@ -72,66 +127,50 @@ TEST(AtomMatcherTest, TestFieldTranslation_ALL) {
EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask);
}
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(AtomMatcherTest, TestFilter_ALL) {
-// FieldMatcher matcher1;
-// matcher1.set_field(10);
-// FieldMatcher* child = matcher1.add_child();
-// child->set_field(1);
-// child->set_position(Position::ALL);
-//
-// child->add_child()->set_field(1);
-// child->add_child()->set_field(2);
-//
-// child = matcher1.add_child();
-// child->set_field(2);
-//
-// vector<Matcher> matchers;
-// translateFieldMatcher(matcher1, &matchers);
-//
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1111);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// AttributionNodeInternal attribution_node3;
-// attribution_node3.set_uid(3333);
-// attribution_node3.set_tag("location3");
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
-// attribution_node3};
-//
-// // Set up the event
-// LogEvent event(10, 12345);
-// event.write(attribution_nodes);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-// HashableDimensionKey output;
-//
-// filterValues(matchers, event.getValues(), &output);
-//
-// EXPECT_EQ((size_t)7, output.getValues().size());
-// EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
-// EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
-// EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
-// EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
-//
-// EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
-// EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
-// EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
-// EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
-//
-// EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
-// EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
-// EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
-// EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
-//
-// EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
-// EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
-//}
+TEST(AtomMatcherTest, TestFilter_ALL) {
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::ALL);
+
+ child->add_child()->set_field(1);
+ child->add_child()->set_field(2);
+
+ child = matcher1.add_child();
+ child->set_field(2);
+
+ vector<Matcher> matchers;
+ translateFieldMatcher(matcher1, &matchers);
+
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event, 10 /*atomId*/, 1012345, attributionUids, attributionTags, "some value");
+ HashableDimensionKey output;
+
+ filterValues(matchers, event.getValues(), &output);
+
+ EXPECT_EQ((size_t)7, output.getValues().size());
+ EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
+ EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
+ EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
+ EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
+ EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
+ EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
+ EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
+ EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
+}
TEST(AtomMatcherTest, TestSubDimension) {
HashableDimensionKey dim;
@@ -174,61 +213,45 @@ TEST(AtomMatcherTest, TestSubDimension) {
EXPECT_TRUE(dim.contains(subDim4));
}
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(AtomMatcherTest, TestMetric2ConditionLink) {
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1111);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// AttributionNodeInternal attribution_node3;
-// attribution_node3.set_uid(3333);
-// attribution_node3.set_tag("location3");
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
-// attribution_node3};
-//
-// // Set up the event
-// LogEvent event(10, 12345);
-// event.write(attribution_nodes);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-//
-// FieldMatcher whatMatcher;
-// whatMatcher.set_field(10);
-// FieldMatcher* child11 = whatMatcher.add_child();
-// child11->set_field(1);
-// child11->set_position(Position::ANY);
-// child11 = child11->add_child();
-// child11->set_field(1);
-//
-// FieldMatcher conditionMatcher;
-// conditionMatcher.set_field(27);
-// FieldMatcher* child2 = conditionMatcher.add_child();
-// child2->set_field(2);
-// child2->set_position(Position::LAST);
-//
-// child2 = child2->add_child();
-// child2->set_field(2);
-//
-// Metric2Condition link;
-//
-// translateFieldMatcher(whatMatcher, &link.metricFields);
-// translateFieldMatcher(conditionMatcher, &link.conditionFields);
-//
-// EXPECT_EQ((size_t)1, link.metricFields.size());
-// EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
-// EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
-// EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
-//
-// EXPECT_EQ((size_t)1, link.conditionFields.size());
-// EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
-// EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
-// EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
-//}
+TEST(AtomMatcherTest, TestMetric2ConditionLink) {
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event, 10 /*atomId*/, 12345, attributionUids, attributionTags, "some value");
+
+ FieldMatcher whatMatcher;
+ whatMatcher.set_field(10);
+ FieldMatcher* child11 = whatMatcher.add_child();
+ child11->set_field(1);
+ child11->set_position(Position::ANY);
+ child11 = child11->add_child();
+ child11->set_field(1);
+
+ FieldMatcher conditionMatcher;
+ conditionMatcher.set_field(27);
+ FieldMatcher* child2 = conditionMatcher.add_child();
+ child2->set_field(2);
+ child2->set_position(Position::LAST);
+
+ child2 = child2->add_child();
+ child2->set_field(2);
+
+ Metric2Condition link;
+
+ translateFieldMatcher(whatMatcher, &link.metricFields);
+ translateFieldMatcher(conditionMatcher, &link.conditionFields);
+
+ EXPECT_EQ((size_t)1, link.metricFields.size());
+ EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
+ EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
+
+ EXPECT_EQ((size_t)1, link.conditionFields.size());
+ EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
+ EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
+}
TEST(AtomMatcherTest, TestWriteDimensionPath) {
for (auto position : {Position::ANY, Position::ALL, Position::FIRST, Position::LAST}) {
@@ -439,50 +462,38 @@ TEST(AtomMatcherTest, TestWriteDimensionLeafNodesToProto) {
EXPECT_EQ(99999, dim4.value_long());
}
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(AtomMatcherTest, TestWriteAtomToProto) {
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1111);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2};
-//
-// // Set up the event
-// LogEvent event(4, 12345);
-// event.write(attribution_nodes);
-// event.write((int32_t)999);
-// // Convert to a LogEvent
-// event.init();
-//
-// android::util::ProtoOutputStream protoOutput;
-// writeFieldValueTreeToStream(event.GetTagId(), event.getValues(), &protoOutput);
-//
-// vector<uint8_t> outData;
-// outData.resize(protoOutput.size());
-// size_t pos = 0;
-// sp<ProtoReader> reader = protoOutput.data();
-// while (reader->readBuffer() != NULL) {
-// size_t toRead = reader->currentToRead();
-// std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
-// pos += toRead;
-// reader->move(toRead);
-// }
-//
-// Atom result;
-// EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
-// EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
-// const auto& atom = result.ble_scan_result_received();
-// EXPECT_EQ(2, atom.attribution_node_size());
-// EXPECT_EQ(1111, atom.attribution_node(0).uid());
-// EXPECT_EQ("location1", atom.attribution_node(0).tag());
-// EXPECT_EQ(2222, atom.attribution_node(1).uid());
-// EXPECT_EQ("location2", atom.attribution_node(1).tag());
-// EXPECT_EQ(999, atom.num_results());
-//}
+TEST(AtomMatcherTest, TestWriteAtomToProto) {
+ std::vector<int> attributionUids = {1111, 2222};
+ std::vector<string> attributionTags = {"location1", "location2"};
+
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event, 4 /*atomId*/, 12345, attributionUids, attributionTags, 999);
+
+ android::util::ProtoOutputStream protoOutput;
+ writeFieldValueTreeToStream(event.GetTagId(), event.getValues(), &protoOutput);
+
+ vector<uint8_t> outData;
+ outData.resize(protoOutput.size());
+ size_t pos = 0;
+ sp<ProtoReader> reader = protoOutput.data();
+ while (reader->readBuffer() != NULL) {
+ size_t toRead = reader->currentToRead();
+ std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
+ pos += toRead;
+ reader->move(toRead);
+ }
+
+ Atom result;
+ EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
+ const auto& atom = result.ble_scan_result_received();
+ EXPECT_EQ(2, atom.attribution_node_size());
+ EXPECT_EQ(1111, atom.attribution_node(0).uid());
+ EXPECT_EQ("location1", atom.attribution_node(0).tag());
+ EXPECT_EQ(2222, atom.attribution_node(1).uid());
+ EXPECT_EQ("location2", atom.attribution_node(1).tag());
+ EXPECT_EQ(999, atom.num_results());
+}
/*
* Test two Matchers is not a subset of one Matcher.
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 2de637714947..6f4c8e48eff2 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -12,18 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/matcher_util.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-
#include <gtest/gtest.h>
#include <log/log_event_list.h>
#include <log/log_read.h>
#include <log/logprint.h>
-
#include <stdio.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/matcher_util.h"
+#include "stats_event.h"
+#include "stats_log_util.h"
+#include "stats_util.h"
+#include "statsd_test_util.h"
+
using namespace android::os::statsd;
using std::unordered_map;
using std::vector;
@@ -39,646 +40,691 @@ const int ATTRIBUTION_TAG_FIELD_ID = 2;
#ifdef __ANDROID__
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AtomMatcherTest, TestSimpleMatcher) {
-// UidMap uidMap;
-//
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-//
-// LogEvent event(TAG_ID, 0);
-// EXPECT_TRUE(event.write(11));
-// event.init();
-//
-// // Test
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Wrong tag id.
-// simpleMatcher->set_atom_id(TAG_ID + 1);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestAttributionMatcher) {
-// UidMap uidMap;
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1111);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// AttributionNodeInternal attribution_node3;
-// attribution_node3.set_uid(3333);
-// attribution_node3.set_tag("location3");
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
-// attribution_node3};
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(attribution_nodes);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-//
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-//
-// // Match first node.
-// auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-// attributionMatcher->set_field(FIELD_ID_1);
-// attributionMatcher->set_position(Position::FIRST);
-// attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-// ATTRIBUTION_TAG_FIELD_ID);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("tag");
-//
-// auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-// fieldMatcher->set_field(FIELD_ID_2);
-// fieldMatcher->set_eq_string("some value");
-//
-// // Tag not matched.
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location3");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Match last node.
-// attributionMatcher->set_position(Position::LAST);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Match any node.
-// attributionMatcher->set_position(Position::ANY);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location2");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location4");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Attribution match but primitive field not match.
-// attributionMatcher->set_position(Position::ANY);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("location2");
-// fieldMatcher->set_eq_string("wrong value");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// fieldMatcher->set_eq_string("some value");
-//
-// // Uid match.
-// attributionMatcher->set_position(Position::ANY);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_field(
-// ATTRIBUTION_UID_FIELD_ID);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("pkg0");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// uidMap.updateMap(
-// 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-// {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-// android::String16("v1"), android::String16("v2")},
-// {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-// android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-// {android::String16(""), android::String16(""), android::String16(""),
-// android::String16(""), android::String16("")});
-//
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::FIRST);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::LAST);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Uid + tag.
-// attributionMatcher->set_position(Position::ANY);
-// attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-// ATTRIBUTION_TAG_FIELD_ID);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location2");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::FIRST);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location2");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::LAST);
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg0");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg1");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location2");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg2");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
-// ->set_eq_string("pkg3");
-// attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)
-// ->set_eq_string("location1");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestUidFieldMatcher) {
-// UidMap uidMap;
-// uidMap.updateMap(
-// 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-// {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-// android::String16("v1"), android::String16("v2")},
-// {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-// android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-// {android::String16(""), android::String16(""), android::String16(""),
-// android::String16(""), android::String16("")});
-//
-// // Set up matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-// simpleMatcher->add_field_value_matcher()->set_field(1);
-// simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("pkg0");
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(1111);
-// event.init();
-//
-// LogEvent event2(TAG_ID_2, 0);
-// event2.write(1111);
-// event2.write("some value");
-// event2.init();
-//
-// // Tag not in kAtomsWithUidField
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // Tag found in kAtomsWithUidField and has matching uid
-// simpleMatcher->set_atom_id(TAG_ID_2);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
-//
-// // Tag found in kAtomsWithUidField but has non-matching uid
-// simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("Pkg2");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
-//}
-//
-//TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
-// UidMap uidMap;
-// uidMap.updateMap(
-// 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-// {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-// android::String16("v1"), android::String16("v2")},
-// {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-// android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-// {android::String16(""), android::String16(""), android::String16(""),
-// android::String16(""), android::String16("")});
-//
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1111);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// AttributionNodeInternal attribution_node3;
-// attribution_node3.set_uid(3333);
-// attribution_node3.set_tag("location3");
-//
-// AttributionNodeInternal attribution_node4;
-// attribution_node4.set_uid(1066);
-// attribution_node4.set_tag("location3");
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
-// attribution_node3, attribution_node4};
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(attribution_nodes);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-//
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-//
-// // Match first node.
-// auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-// attributionMatcher->set_field(FIELD_ID_1);
-// attributionMatcher->set_position(Position::FIRST);
-// attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-// ATTRIBUTION_UID_FIELD_ID);
-// auto neqStringList = attributionMatcher->mutable_matches_tuple()
-// ->mutable_field_value_matcher(0)
-// ->mutable_neq_any_string();
-// neqStringList->add_str_value("pkg2");
-// neqStringList->add_str_value("pkg3");
-//
-// auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-// fieldMatcher->set_field(FIELD_ID_2);
-// fieldMatcher->set_eq_string("some value");
-//
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// neqStringList->Clear();
-// neqStringList->add_str_value("pkg1");
-// neqStringList->add_str_value("pkg3");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::ANY);
-// neqStringList->Clear();
-// neqStringList->add_str_value("maps.com");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// neqStringList->Clear();
-// neqStringList->add_str_value("PkG3");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::LAST);
-// neqStringList->Clear();
-// neqStringList->add_str_value("AID_STATSD");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
-// UidMap uidMap;
-// uidMap.updateMap(
-// 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-// {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-// android::String16("v1"), android::String16("v2")},
-// {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-// android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-// {android::String16(""), android::String16(""), android::String16(""),
-// android::String16(""), android::String16("")});
-//
-// AttributionNodeInternal attribution_node1;
-// attribution_node1.set_uid(1067);
-// attribution_node1.set_tag("location1");
-//
-// AttributionNodeInternal attribution_node2;
-// attribution_node2.set_uid(2222);
-// attribution_node2.set_tag("location2");
-//
-// AttributionNodeInternal attribution_node3;
-// attribution_node3.set_uid(3333);
-// attribution_node3.set_tag("location3");
-//
-// AttributionNodeInternal attribution_node4;
-// attribution_node4.set_uid(1066);
-// attribution_node4.set_tag("location3");
-// std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
-// attribution_node3, attribution_node4};
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(attribution_nodes);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-//
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-//
-// // Match first node.
-// auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-// attributionMatcher->set_field(FIELD_ID_1);
-// attributionMatcher->set_position(Position::FIRST);
-// attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-// ATTRIBUTION_UID_FIELD_ID);
-// auto eqStringList = attributionMatcher->mutable_matches_tuple()
-// ->mutable_field_value_matcher(0)
-// ->mutable_eq_any_string();
-// eqStringList->add_str_value("AID_ROOT");
-// eqStringList->add_str_value("AID_INCIDENTD");
-//
-// auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-// fieldMatcher->set_field(FIELD_ID_2);
-// fieldMatcher->set_eq_string("some value");
-//
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// attributionMatcher->set_position(Position::ANY);
-// eqStringList->Clear();
-// eqStringList->add_str_value("AID_STATSD");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// eqStringList->Clear();
-// eqStringList->add_str_value("pkg1");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// auto normalStringField = fieldMatcher->mutable_eq_any_string();
-// normalStringField->add_str_value("some value123");
-// normalStringField->add_str_value("some value");
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// normalStringField->Clear();
-// normalStringField->add_str_value("AID_STATSD");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// eqStringList->Clear();
-// eqStringList->add_str_value("maps.com");
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestBoolMatcher) {
-// UidMap uidMap;
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-// auto keyValue1 = simpleMatcher->add_field_value_matcher();
-// keyValue1->set_field(FIELD_ID_1);
-// auto keyValue2 = simpleMatcher->add_field_value_matcher();
-// keyValue2->set_field(FIELD_ID_2);
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// EXPECT_TRUE(event.write(true));
-// EXPECT_TRUE(event.write(false));
-// // Convert to a LogEvent
-// event.init();
-//
-// // Test
-// keyValue1->set_eq_bool(true);
-// keyValue2->set_eq_bool(false);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// keyValue1->set_eq_bool(false);
-// keyValue2->set_eq_bool(false);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// keyValue1->set_eq_bool(false);
-// keyValue2->set_eq_bool(true);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// keyValue1->set_eq_bool(true);
-// keyValue2->set_eq_bool(true);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestStringMatcher) {
-// UidMap uidMap;
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-// auto keyValue = simpleMatcher->add_field_value_matcher();
-// keyValue->set_field(FIELD_ID_1);
-// keyValue->set_eq_string("some value");
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write("some value");
-// // Convert to a LogEvent
-// event.init();
-//
-// // Test
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
-// UidMap uidMap;
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-// auto keyValue1 = simpleMatcher->add_field_value_matcher();
-// keyValue1->set_field(FIELD_ID_1);
-// auto keyValue2 = simpleMatcher->add_field_value_matcher();
-// keyValue2->set_field(FIELD_ID_2);
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(2);
-// event.write(3);
-//
-// // Convert to a LogEvent
-// event.init();
-//
-// // Test
-// keyValue1->set_eq_int(2);
-// keyValue2->set_eq_int(3);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// keyValue1->set_eq_int(2);
-// keyValue2->set_eq_int(4);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// keyValue1->set_eq_int(4);
-// keyValue2->set_eq_int(3);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestIntComparisonMatcher) {
-// UidMap uidMap;
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-//
-// simpleMatcher->set_atom_id(TAG_ID);
-// auto keyValue = simpleMatcher->add_field_value_matcher();
-// keyValue->set_field(FIELD_ID_1);
-//
-// // Set up the event
-// LogEvent event(TAG_ID, 0);
-// event.write(11);
-// event.init();
-//
-// // Test
-//
-// // eq_int
-// keyValue->set_eq_int(10);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_eq_int(11);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_eq_int(12);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // lt_int
-// keyValue->set_lt_int(10);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_lt_int(11);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_lt_int(12);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // lte_int
-// keyValue->set_lte_int(10);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_lte_int(11);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_lte_int(12);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // gt_int
-// keyValue->set_gt_int(10);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_gt_int(11);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_gt_int(12);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//
-// // gte_int
-// keyValue->set_gte_int(10);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_gte_int(11);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-// keyValue->set_gte_int(12);
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-//}
-//
-//TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
-// UidMap uidMap;
-// // Set up the matcher
-// AtomMatcher matcher;
-// auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-// simpleMatcher->set_atom_id(TAG_ID);
-//
-// auto keyValue = simpleMatcher->add_field_value_matcher();
-// keyValue->set_field(FIELD_ID_1);
-//
-// LogEvent event1(TAG_ID, 0);
-// keyValue->set_lt_float(10.0);
-// event1.write(10.1f);
-// event1.init();
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
-//
-// LogEvent event2(TAG_ID, 0);
-// event2.write(9.9f);
-// event2.init();
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
-//
-// LogEvent event3(TAG_ID, 0);
-// event3.write(10.1f);
-// event3.init();
-// keyValue->set_gt_float(10.0);
-// EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3));
-//
-// LogEvent event4(TAG_ID, 0);
-// event4.write(9.9f);
-// event4.init();
-// EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
-//}
+
+namespace {
+
+void makeIntLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const int32_t value) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ AStatsEvent_writeInt32(statsEvent, value);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeFloatLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const float floatValue) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ AStatsEvent_writeFloat(statsEvent, floatValue);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const string& name) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeIntStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const int32_t value, const string& name) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ AStatsEvent_writeInt32(statsEvent, value);
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeAttributionLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags, const string& name) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
+ const bool bool1, const bool bool2) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
+
+ AStatsEvent_writeBool(statsEvent, bool1);
+ AStatsEvent_writeBool(statsEvent, bool2);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+
+ AStatsEvent_release(statsEvent);
+}
+
+} // anonymous namespace
+
+TEST(AtomMatcherTest, TestSimpleMatcher) {
+ UidMap uidMap;
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeIntLogEvent(&event, TAG_ID, 0, 11);
+
+ // Test
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Wrong tag id.
+ simpleMatcher->set_atom_id(TAG_ID + 1);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestAttributionMatcher) {
+ UidMap uidMap;
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+
+ // Set up the log event.
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ // Match first node.
+ auto attributionMatcher = simpleMatcher->add_field_value_matcher();
+ attributionMatcher->set_field(FIELD_ID_1);
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_TAG_FIELD_ID);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "tag");
+
+ auto fieldMatcher = simpleMatcher->add_field_value_matcher();
+ fieldMatcher->set_field(FIELD_ID_2);
+ fieldMatcher->set_eq_string("some value");
+
+ // Tag not matched.
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Match last node.
+ attributionMatcher->set_position(Position::LAST);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Match any node.
+ attributionMatcher->set_position(Position::ANY);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location2");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location4");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Attribution match but primitive field not match.
+ attributionMatcher->set_position(Position::ANY);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "location2");
+ fieldMatcher->set_eq_string("wrong value");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ fieldMatcher->set_eq_string("some value");
+
+ // Uid match.
+ attributionMatcher->set_position(Position::ANY);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_field(
+ ATTRIBUTION_UID_FIELD_ID);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+ android::String16("v1"), android::String16("v2")},
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
+ {android::String16(""), android::String16(""), android::String16(""),
+ android::String16(""), android::String16("")});
+
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::LAST);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Uid + tag.
+ attributionMatcher->set_position(Position::ANY);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_TAG_FIELD_ID);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location2");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location2");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::LAST);
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg0");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg1");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location2");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg2");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
+ "pkg3");
+ attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
+ "location1");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestUidFieldMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+ android::String16("v1"), android::String16("v2")},
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
+ {android::String16(""), android::String16(""), android::String16(""),
+ android::String16(""), android::String16("")});
+
+ // Set up matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+ simpleMatcher->add_field_value_matcher()->set_field(1);
+ simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("pkg0");
+
+ // Set up the event
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeIntLogEvent(&event1, TAG_ID, 0, 1111);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeIntStringLogEvent(&event2, TAG_ID_2, 0, 1111, "some value");
+
+ // Tag not in kAtomsWithUidField
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+ // Tag found in kAtomsWithUidField and has matching uid
+ simpleMatcher->set_atom_id(TAG_ID_2);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+ // Tag found in kAtomsWithUidField but has non-matching uid
+ simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("Pkg2");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+}
+
+TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+ android::String16("v1"), android::String16("v2")},
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
+ {android::String16(""), android::String16(""), android::String16(""),
+ android::String16(""), android::String16("")});
+
+ std::vector<int> attributionUids = {1111, 2222, 3333, 1066};
+ std::vector<string> attributionTags = {"location1", "location2", "location3", "location3"};
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ // Match first node.
+ auto attributionMatcher = simpleMatcher->add_field_value_matcher();
+ attributionMatcher->set_field(FIELD_ID_1);
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_UID_FIELD_ID);
+ auto neqStringList = attributionMatcher->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_neq_any_string();
+ neqStringList->add_str_value("pkg2");
+ neqStringList->add_str_value("pkg3");
+
+ auto fieldMatcher = simpleMatcher->add_field_value_matcher();
+ fieldMatcher->set_field(FIELD_ID_2);
+ fieldMatcher->set_eq_string("some value");
+
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ neqStringList->Clear();
+ neqStringList->add_str_value("pkg1");
+ neqStringList->add_str_value("pkg3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::ANY);
+ neqStringList->Clear();
+ neqStringList->add_str_value("maps.com");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ neqStringList->Clear();
+ neqStringList->add_str_value("PkG3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::LAST);
+ neqStringList->Clear();
+ neqStringList->add_str_value("AID_STATSD");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+ android::String16("v1"), android::String16("v2")},
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
+ {android::String16(""), android::String16(""), android::String16(""),
+ android::String16(""), android::String16("")});
+
+ std::vector<int> attributionUids = {1067, 2222, 3333, 1066};
+ std::vector<string> attributionTags = {"location1", "location2", "location3", "location3"};
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ // Match first node.
+ auto attributionMatcher = simpleMatcher->add_field_value_matcher();
+ attributionMatcher->set_field(FIELD_ID_1);
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_UID_FIELD_ID);
+ auto eqStringList = attributionMatcher->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_eq_any_string();
+ eqStringList->add_str_value("AID_ROOT");
+ eqStringList->add_str_value("AID_INCIDENTD");
+
+ auto fieldMatcher = simpleMatcher->add_field_value_matcher();
+ fieldMatcher->set_field(FIELD_ID_2);
+ fieldMatcher->set_eq_string("some value");
+
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::ANY);
+ eqStringList->Clear();
+ eqStringList->add_str_value("AID_STATSD");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ eqStringList->Clear();
+ eqStringList->add_str_value("pkg1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ auto normalStringField = fieldMatcher->mutable_eq_any_string();
+ normalStringField->add_str_value("some value123");
+ normalStringField->add_str_value("some value");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ normalStringField->Clear();
+ normalStringField->add_str_value("AID_STATSD");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ eqStringList->Clear();
+ eqStringList->add_str_value("maps.com");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestBoolMatcher) {
+ UidMap uidMap;
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+ auto keyValue1 = simpleMatcher->add_field_value_matcher();
+ keyValue1->set_field(FIELD_ID_1);
+ auto keyValue2 = simpleMatcher->add_field_value_matcher();
+ keyValue2->set_field(FIELD_ID_2);
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeBoolLogEvent(&event, TAG_ID, 0, true, false);
+
+ // Test
+ keyValue1->set_eq_bool(true);
+ keyValue2->set_eq_bool(false);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ keyValue1->set_eq_bool(false);
+ keyValue2->set_eq_bool(false);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ keyValue1->set_eq_bool(false);
+ keyValue2->set_eq_bool(true);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ keyValue1->set_eq_bool(true);
+ keyValue2->set_eq_bool(true);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestStringMatcher) {
+ UidMap uidMap;
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+ auto keyValue = simpleMatcher->add_field_value_matcher();
+ keyValue->set_field(FIELD_ID_1);
+ keyValue->set_eq_string("some value");
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeStringLogEvent(&event, TAG_ID, 0, "some value");
+
+ // Test
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
+ UidMap uidMap;
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+ auto keyValue1 = simpleMatcher->add_field_value_matcher();
+ keyValue1->set_field(FIELD_ID_1);
+ auto keyValue2 = simpleMatcher->add_field_value_matcher();
+ keyValue2->set_field(FIELD_ID_2);
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event, TAG_ID, 0, 2, 3);
+
+ // Test
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(3);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(4);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ keyValue1->set_eq_int(4);
+ keyValue2->set_eq_int(3);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestIntComparisonMatcher) {
+ UidMap uidMap;
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+
+ simpleMatcher->set_atom_id(TAG_ID);
+ auto keyValue = simpleMatcher->add_field_value_matcher();
+ keyValue->set_field(FIELD_ID_1);
+
+ // Set up the event
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeIntLogEvent(&event, TAG_ID, 0, 11);
+
+ // Test
+
+ // eq_int
+ keyValue->set_eq_int(10);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_eq_int(11);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_eq_int(12);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // lt_int
+ keyValue->set_lt_int(10);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_lt_int(11);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_lt_int(12);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // lte_int
+ keyValue->set_lte_int(10);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_lte_int(11);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_lte_int(12);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // gt_int
+ keyValue->set_gt_int(10);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_gt_int(11);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_gt_int(12);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // gte_int
+ keyValue->set_gte_int(10);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_gte_int(11);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ keyValue->set_gte_int(12);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
+ UidMap uidMap;
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ auto keyValue = simpleMatcher->add_field_value_matcher();
+ keyValue->set_field(FIELD_ID_1);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeFloatLogEvent(&event1, TAG_ID, 0, 10.1f);
+ keyValue->set_lt_float(10.0);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeFloatLogEvent(&event2, TAG_ID, 0, 9.9f);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeFloatLogEvent(&event3, TAG_ID, 0, 10.1f);
+ keyValue->set_gt_float(10.0);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3));
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeFloatLogEvent(&event4, TAG_ID, 0, 9.9f);
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
+}
// Helper for the composite matchers.
void addSimpleMatcher(SimpleAtomMatcher* simpleMatcher, int tag, int key, int val) {
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index d6498f4f1554..9e7b7c820e0d 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -253,1416 +253,1420 @@ TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
EXPECT_EQ(2, report.annotation(0).field_int32());
}
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(StatsLogProcessorTest, TestOnDumpReportEraseData) {
-// // Setup a simple config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = wakelockAcquireMatcher;
-//
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(123456);
-// countMetric->set_what(wakelockAcquireMatcher.id());
-// countMetric->set_bucket(FIVE_MINUTES);
-//
-// ConfigKey cfgKey;
-// sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 2);
-// processor->OnLogEvent(event.get());
-//
-// vector<uint8_t> bytes;
-// ConfigMetricsReportList output;
-//
-// // Dump report WITHOUT erasing data.
-// processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST, &bytes);
-// output.ParseFromArray(bytes.data(), bytes.size());
-// EXPECT_EQ(output.reports_size(), 1);
-// EXPECT_EQ(output.reports(0).metrics_size(), 1);
-// EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
-//
-// // Dump report WITH erasing data. There should be data since we didn't previously erase it.
-// processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
-// output.ParseFromArray(bytes.data(), bytes.size());
-// EXPECT_EQ(output.reports_size(), 1);
-// EXPECT_EQ(output.reports(0).metrics_size(), 1);
-// EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
-//
-// // Dump report again. There should be no data since we erased it.
-// processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
-// output.ParseFromArray(bytes.data(), bytes.size());
-// // We don't care whether statsd has a report, as long as it has no count metrics in it.
-// bool noData = output.reports_size() == 0
-// || output.reports(0).metrics_size() == 0
-// || output.reports(0).metrics(0).count_metrics().data_size() == 0;
-// EXPECT_TRUE(noData);
-//}
-//
-//TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
-// int uid = 1111;
-//
-// // Setup a simple config, no activation
-// StatsdConfig config1;
-// 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;
-//
-// long metricId1 = 1234561;
-// long metricId2 = 1234562;
-// auto countMetric1 = config1.add_count_metric();
-// countMetric1->set_id(metricId1);
-// countMetric1->set_what(wakelockAcquireMatcher.id());
-// countMetric1->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric2 = config1.add_count_metric();
-// countMetric2->set_id(metricId2);
-// countMetric2->set_what(wakelockAcquireMatcher.id());
-// countMetric2->set_bucket(FIVE_MINUTES);
-//
-// ConfigKey cfgKey1(uid, cfgId1);
-//
-// // Add another config, with two metrics, one with activation
-// StatsdConfig config2;
-// 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;
-//
-// long metricId3 = 1234561;
-// long metricId4 = 1234562;
-//
-// auto countMetric3 = config2.add_count_metric();
-// countMetric3->set_id(metricId3);
-// countMetric3->set_what(wakelockAcquireMatcher.id());
-// countMetric3->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric4 = config2.add_count_metric();
-// countMetric4->set_id(metricId4);
-// countMetric4->set_what(wakelockAcquireMatcher.id());
-// countMetric4->set_bucket(FIVE_MINUTES);
-//
-// auto metric3Activation = config2.add_metric_activation();
-// metric3Activation->set_metric_id(metricId3);
-// metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto metric3ActivationTrigger = metric3Activation->add_event_activation();
-// metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric3ActivationTrigger->set_ttl_seconds(100);
-//
-// ConfigKey cfgKey2(uid, cfgId2);
-//
-// // Add another config, with two metrics, both with activations
-// StatsdConfig config3;
-// 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;
-//
-// long metricId5 = 1234565;
-// long metricId6 = 1234566;
-// auto countMetric5 = config3.add_count_metric();
-// countMetric5->set_id(metricId5);
-// countMetric5->set_what(wakelockAcquireMatcher.id());
-// countMetric5->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric6 = config3.add_count_metric();
-// countMetric6->set_id(metricId6);
-// countMetric6->set_what(wakelockAcquireMatcher.id());
-// countMetric6->set_bucket(FIVE_MINUTES);
-//
-// auto metric5Activation = config3.add_metric_activation();
-// metric5Activation->set_metric_id(metricId5);
-// metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto metric5ActivationTrigger = metric5Activation->add_event_activation();
-// metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric5ActivationTrigger->set_ttl_seconds(100);
-//
-// auto metric6Activation = config3.add_metric_activation();
-// metric6Activation->set_metric_id(metricId6);
-// metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto metric6ActivationTrigger = metric6Activation->add_event_activation();
-// metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric6ActivationTrigger->set_ttl_seconds(200);
-//
-// ConfigKey cfgKey3(uid, cfgId3);
-//
-// 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,
-// 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());
-//
-// auto metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer1 = *metricIt;
-// EXPECT_TRUE(metricProducer1->isActive());
-//
-// metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer2 = *metricIt;
-// EXPECT_TRUE(metricProducer2->isActive());
-//
-// // 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());
-//
-// metricIt = metricsManager2->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId3) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
-// auto& metricProducer3 = *metricIt;
-// EXPECT_FALSE(metricProducer3->isActive());
-//
-// metricIt = metricsManager2->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId4) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
-// auto& metricProducer4 = *metricIt;
-// EXPECT_TRUE(metricProducer4->isActive());
-//
-// // 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());
-//
-// metricIt = metricsManager3->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId5) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
-// auto& metricProducer5 = *metricIt;
-// EXPECT_FALSE(metricProducer5->isActive());
-//
-// metricIt = metricsManager3->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId6) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
-// 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());
-//
-// // 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;
-// processor.SaveActiveConfigsToDisk(shutDownTime);
-// const int64_t ttl3 = event->GetElapsedTimestampNs() +
-// metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-// const int64_t ttl5 = event->GetElapsedTimestampNs() +
-// metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-// const int64_t ttl6 = event->GetElapsedTimestampNs() +
-// metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-//
-// // Create a second StatsLogProcessor and push the same 3 configs.
-// long timeBase2 = 1000;
-// sp<StatsLogProcessor> processor2 =
-// CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-// processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
-// 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;
-// EXPECT_TRUE(metricsManager1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1001 = *metricIt;
-// EXPECT_TRUE(metricProducer1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1002 = *metricIt;
-// EXPECT_TRUE(metricProducer1002->isActive());
-//
-// // 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;
-// EXPECT_TRUE(metricsManager1002->isActive());
-//
-// metricIt = metricsManager1002->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId3) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
-// auto& metricProducer1003 = *metricIt;
-// EXPECT_FALSE(metricProducer1003->isActive());
-//
-// metricIt = metricsManager1002->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId4) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
-// 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;
-// EXPECT_FALSE(metricsManager1003->isActive());
-// EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size());
-//
-// metricIt = metricsManager1003->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId5) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
-// auto& metricProducer1005 = *metricIt;
-// EXPECT_FALSE(metricProducer1005->isActive());
-//
-// metricIt = metricsManager1003->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId6) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
-// 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);
-// EXPECT_EQ(0, activation1003->start_ns);
-// EXPECT_FALSE(metricProducer1005->isActive());
-// const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
-// EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns);
-// EXPECT_EQ(0, activation1005->start_ns);
-// EXPECT_FALSE(metricProducer1006->isActive());
-// const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
-// EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns);
-// EXPECT_EQ(0, activation1006->start_ns);
-//
-// processor2->LoadActiveConfigsFromDisk();
-//
-// // After loading activations from disk, assert that all 3 metrics are active.
-// EXPECT_TRUE(metricProducer1003->isActive());
-// EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
-// EXPECT_TRUE(metricProducer1005->isActive());
-// EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
-// EXPECT_TRUE(metricProducer1006->isActive());
-// EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
-//
-// // Make sure no more broadcasts have happened.
-// EXPECT_EQ(broadcastCount, 1);
-//}
-//
-//TEST(StatsLogProcessorTest, TestActivationOnBoot) {
-// int uid = 1111;
-//
-// StatsdConfig config1;
-// config1.set_id(12341);
-// config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-// *config1.add_atom_matcher() = wakelockAcquireMatcher;
-//
-// long metricId1 = 1234561;
-// long metricId2 = 1234562;
-// auto countMetric1 = config1.add_count_metric();
-// countMetric1->set_id(metricId1);
-// countMetric1->set_what(wakelockAcquireMatcher.id());
-// countMetric1->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric2 = config1.add_count_metric();
-// countMetric2->set_id(metricId2);
-// countMetric2->set_what(wakelockAcquireMatcher.id());
-// countMetric2->set_bucket(FIVE_MINUTES);
-//
-// auto metric1Activation = config1.add_metric_activation();
-// metric1Activation->set_metric_id(metricId1);
-// metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-// auto metric1ActivationTrigger = metric1Activation->add_event_activation();
-// metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric1ActivationTrigger->set_ttl_seconds(100);
-//
-// ConfigKey cfgKey1(uid, 12341);
-// long timeBase1 = 1;
-// sp<StatsLogProcessor> processor =
-// CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-//
-// EXPECT_EQ(1, processor->mMetricsManagers.size());
-// auto it = processor->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor->mMetricsManagers.end());
-// auto& metricsManager1 = it->second;
-// EXPECT_TRUE(metricsManager1->isActive());
-//
-// auto metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer1 = *metricIt;
-// EXPECT_FALSE(metricProducer1->isActive());
-//
-// metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer2 = *metricIt;
-// EXPECT_TRUE(metricProducer2->isActive());
-//
-// const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
-// EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kNotActive, activation1->state);
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
-// processor->OnLogEvent(event.get());
-//
-// EXPECT_FALSE(metricProducer1->isActive());
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1->state);
-//
-// int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-// processor->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_FALSE(metricProducer1->isActive());
-// const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
-//
-// long timeBase2 = 1000;
-// sp<StatsLogProcessor> processor2 =
-// CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-//
-// EXPECT_EQ(1, processor2->mMetricsManagers.size());
-// it = processor2->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-// auto& metricsManager1001 = it->second;
-// EXPECT_TRUE(metricsManager1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1001 = *metricIt;
-// EXPECT_FALSE(metricProducer1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1002 = *metricIt;
-// EXPECT_TRUE(metricProducer1002->isActive());
-//
-// const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
-// EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
-// EXPECT_EQ(0, activation1001->start_ns);
-// EXPECT_EQ(kNotActive, activation1001->state);
-//
-// processor2->LoadActiveConfigsFromDisk();
-//
-// EXPECT_TRUE(metricProducer1001->isActive());
-// EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
-// EXPECT_EQ(kActive, activation1001->state);
-//}
-//
-//TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
-// int uid = 1111;
-//
-// // Create config with 2 metrics:
-// // Metric 1: Activate on boot with 2 activations
-// // Metric 2: Always active
-// StatsdConfig config1;
-// config1.set_id(12341);
-// config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config1.add_atom_matcher() = wakelockAcquireMatcher;
-// *config1.add_atom_matcher() = screenOnMatcher;
-//
-// long metricId1 = 1234561;
-// long metricId2 = 1234562;
-//
-// auto countMetric1 = config1.add_count_metric();
-// countMetric1->set_id(metricId1);
-// countMetric1->set_what(wakelockAcquireMatcher.id());
-// countMetric1->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric2 = config1.add_count_metric();
-// countMetric2->set_id(metricId2);
-// countMetric2->set_what(wakelockAcquireMatcher.id());
-// countMetric2->set_bucket(FIVE_MINUTES);
-//
-// auto metric1Activation = config1.add_metric_activation();
-// metric1Activation->set_metric_id(metricId1);
-// metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-// auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric1ActivationTrigger1->set_ttl_seconds(100);
-// auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-// metric1ActivationTrigger2->set_ttl_seconds(200);
-//
-// ConfigKey cfgKey1(uid, 12341);
-// long timeBase1 = 1;
-// sp<StatsLogProcessor> processor =
-// CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor->mMetricsManagers.size());
-// auto it = processor->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor->mMetricsManagers.end());
-// auto& metricsManager1 = it->second;
-// EXPECT_TRUE(metricsManager1->isActive());
-//
-// auto metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer1 = *metricIt;
-// EXPECT_FALSE(metricProducer1->isActive());
-//
-// metricIt = metricsManager1->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-// auto& metricProducer2 = *metricIt;
-// EXPECT_TRUE(metricProducer2->isActive());
-//
-// int i = 0;
-// for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
-// if (metricsManager1->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger1->atom_matcher_id()) {
-// break;
-// }
-// }
-// const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kNotActive, activation1->state);
-//
-// i = 0;
-// for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
-// if (metricsManager1->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger2->atom_matcher_id()) {
-// break;
-// }
-// }
-// const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
-// EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
-// EXPECT_EQ(0, activation2->start_ns);
-// EXPECT_EQ(kNotActive, activation2->state);
-// // }}}------------------------------------------------------------------------------
-//
-// // Trigger Activation 1 for Metric 1
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
-// processor->OnLogEvent(event.get());
-//
-// // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_FALSE(metricProducer1->isActive());
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1->state);
-// EXPECT_EQ(0, activation2->start_ns);
-// EXPECT_EQ(kNotActive, activation2->state);
-//
-// EXPECT_TRUE(metricProducer2->isActive());
-// // }}}-----------------------------------------------------------------------------
-//
-// // Simulate shutdown by saving state to disk
-// int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-// processor->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_FALSE(metricProducer1->isActive());
-// int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
-//
-// // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-// // same config.
-// long timeBase2 = 1000;
-// sp<StatsLogProcessor> processor2 =
-// CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor2->mMetricsManagers.size());
-// it = processor2->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-// auto& metricsManager1001 = it->second;
-// EXPECT_TRUE(metricsManager1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1001 = *metricIt;
-// EXPECT_FALSE(metricProducer1001->isActive());
-//
-// metricIt = metricsManager1001->mAllMetricProducers.begin();
-// for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-// auto& metricProducer1002 = *metricIt;
-// EXPECT_TRUE(metricProducer1002->isActive());
-//
-// i = 0;
-// for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
-// if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger1->atom_matcher_id()) {
-// break;
-// }
-// }
-// const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
-// EXPECT_EQ(0, activation1001_1->start_ns);
-// EXPECT_EQ(kNotActive, activation1001_1->state);
-//
-// i = 0;
-// for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
-// if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger2->atom_matcher_id()) {
-// break;
-// }
-// }
-//
-// const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
-// EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
-// EXPECT_EQ(0, activation1001_2->start_ns);
-// EXPECT_EQ(kNotActive, activation1001_2->state);
-// // }}}-----------------------------------------------------------------------------------
-//
-// // Load saved state from disk.
-// processor2->LoadActiveConfigsFromDisk();
-//
-// // Metric 1 active; Activation 1 is active, Activation 2 is not active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer1001->isActive());
-// EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
-// EXPECT_EQ(kActive, activation1001_1->state);
-// EXPECT_EQ(0, activation1001_2->start_ns);
-// EXPECT_EQ(kNotActive, activation1001_2->state);
-//
-// EXPECT_TRUE(metricProducer1002->isActive());
-// // }}}--------------------------------------------------------------------------------
-//
-// // Trigger Activation 2 for Metric 1.
-// auto screenOnEvent = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_ON,
-// timeBase2 + 200
-// );
-// processor2->OnLogEvent(screenOnEvent.get());
-//
-// // Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer1001->isActive());
-// EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
-// EXPECT_EQ(kActive, activation1001_1->state);
-// EXPECT_EQ(0, activation1001_2->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
-//
-// EXPECT_TRUE(metricProducer1002->isActive());
-// // }}}---------------------------------------------------------------------------
-//
-// // Simulate shutdown by saving state to disk
-// shutDownTime = timeBase2 + 50 * NS_PER_SEC;
-// processor2->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_TRUE(metricProducer1001->isActive());
-// EXPECT_TRUE(metricProducer1002->isActive());
-// ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
-// int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
-//
-// // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-// // same config.
-// long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
-// sp<StatsLogProcessor> processor3 =
-// CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor3->mMetricsManagers.size());
-// it = processor3->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor3->mMetricsManagers.end());
-// auto& metricsManagerTimeBase3 = it->second;
-// EXPECT_TRUE(metricsManagerTimeBase3->isActive());
-//
-// metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
-// for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
-// auto& metricProducerTimeBase3_1 = *metricIt;
-// EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
-//
-// metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
-// for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
-// auto& metricProducerTimeBase3_2 = *metricIt;
-// EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-//
-// i = 0;
-// for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
-// if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger1->atom_matcher_id()) {
-// break;
-// }
-// }
-// const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
-// EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
-// EXPECT_EQ(0, activationTimeBase3_1->start_ns);
-// EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
-//
-// i = 0;
-// for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
-// if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger2->atom_matcher_id()) {
-// break;
-// }
-// }
-//
-// const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
-// EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
-// EXPECT_EQ(0, activationTimeBase3_2->start_ns);
-// EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
-//
-// EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-// // }}}----------------------------------------------------------------------------------
-//
-// // Load saved state from disk.
-// processor3->LoadActiveConfigsFromDisk();
-//
-// // Metric 1 active: Activation 1 is active, Activation 2 is active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
-// EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
-// EXPECT_EQ(kActive, activationTimeBase3_1->state);
-// EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
-// EXPECT_EQ(kActive, activationTimeBase3_2->state);
-//
-// EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-// // }}}-------------------------------------------------------------------------------
-//
-// // Trigger Activation 2 for Metric 1 again.
-// screenOnEvent = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_ON,
-// timeBase3 + 100 * NS_PER_SEC
-// );
-// processor3->OnLogEvent(screenOnEvent.get());
-//
-// // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
-// EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
-// EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
-// EXPECT_EQ(kActive, activationTimeBase3_2->state);
-//
-// EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-// // }}}---------------------------------------------------------------------------
-//
-// // Simulate shutdown by saving state to disk.
-// shutDownTime = timeBase3 + 500 * NS_PER_SEC;
-// processor3->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_TRUE(metricProducer1001->isActive());
-// EXPECT_TRUE(metricProducer1002->isActive());
-// ttl1 = timeBase3 + ttl1 - shutDownTime;
-// ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
-//
-// // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-// // same config.
-// long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
-// sp<StatsLogProcessor> processor4 =
-// CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor4->mMetricsManagers.size());
-// it = processor4->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor4->mMetricsManagers.end());
-// auto& metricsManagerTimeBase4 = it->second;
-// EXPECT_TRUE(metricsManagerTimeBase4->isActive());
-//
-// metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
-// for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId1) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
-// auto& metricProducerTimeBase4_1 = *metricIt;
-// EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
-//
-// metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
-// for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
-// if ((*metricIt)->getMetricId() == metricId2) {
-// break;
-// }
-// }
-// EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
-// auto& metricProducerTimeBase4_2 = *metricIt;
-// EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-//
-// i = 0;
-// for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
-// if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger1->atom_matcher_id()) {
-// break;
-// }
-// }
-// const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
-// EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
-// EXPECT_EQ(0, activationTimeBase4_1->start_ns);
-// EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
-//
-// i = 0;
-// for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
-// if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
-// metric1ActivationTrigger2->atom_matcher_id()) {
-// break;
-// }
-// }
-//
-// const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
-// EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
-// EXPECT_EQ(0, activationTimeBase4_2->start_ns);
-// EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
-//
-// EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-// // }}}----------------------------------------------------------------------------------
-//
-// // Load saved state from disk.
-// processor4->LoadActiveConfigsFromDisk();
-//
-// // Metric 1 active: Activation 1 is not active, Activation 2 is not active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
-// EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
-// EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
-//
-// EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-// // }}}-------------------------------------------------------------------------------
-//}
-//
-//TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
-// int uid = 1111;
-//
-// // Create config with 2 metrics:
-// // Metric 1: Activate on boot with 2 activations
-// // Metric 2: Always active
-// StatsdConfig config1;
-// config1.set_id(12341);
-// config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config1.add_atom_matcher() = wakelockAcquireMatcher;
-// *config1.add_atom_matcher() = screenOnMatcher;
-//
-// long metricId1 = 1234561;
-// long metricId2 = 1234562;
-//
-// auto countMetric1 = config1.add_count_metric();
-// countMetric1->set_id(metricId1);
-// countMetric1->set_what(wakelockAcquireMatcher.id());
-// countMetric1->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric2 = config1.add_count_metric();
-// countMetric2->set_id(metricId2);
-// countMetric2->set_what(wakelockAcquireMatcher.id());
-// countMetric2->set_bucket(FIVE_MINUTES);
-//
-// auto metric1Activation = config1.add_metric_activation();
-// metric1Activation->set_metric_id(metricId1);
-// metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-// auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric1ActivationTrigger1->set_ttl_seconds(100);
-// auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-// metric1ActivationTrigger2->set_ttl_seconds(200);
-// metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-//
-// ConfigKey cfgKey1(uid, 12341);
-// long timeBase1 = 1;
-// sp<StatsLogProcessor> processor1 =
-// CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor1->mMetricsManagers.size());
-// auto it = processor1->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor1->mMetricsManagers.end());
-// auto& metricsManager1 = it->second;
-// EXPECT_TRUE(metricsManager1->isActive());
-//
-// EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
-// // We assume that the index of a MetricProducer within the mAllMetricProducers
-// // array follows the order in which metrics are added to the config.
-// auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
-// EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
-//
-// auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
-// EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
-// EXPECT_TRUE(metricProducer1_2->isActive());
-//
-// EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
-// // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-// // that matchers are indexed in the order that they are added to the config.
-// const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
-// EXPECT_EQ(0, activation1_1_1->start_ns);
-// EXPECT_EQ(kNotActive, activation1_1_1->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
-//
-// const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
-// EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
-// EXPECT_EQ(0, activation1_1_2->start_ns);
-// EXPECT_EQ(kNotActive, activation1_1_2->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
-// // }}}------------------------------------------------------------------------------
-//
-// // Trigger Activation 1 for Metric 1
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
-// processor1->OnLogEvent(event.get());
-//
-// // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_FALSE(metricProducer1_1->isActive());
-// EXPECT_EQ(0, activation1_1_1->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
-// EXPECT_EQ(0, activation1_1_2->start_ns);
-// EXPECT_EQ(kNotActive, activation1_1_2->state);
-//
-// EXPECT_TRUE(metricProducer1_2->isActive());
-// // }}}-----------------------------------------------------------------------------
-//
-// // Simulate shutdown by saving state to disk
-// int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-// processor1->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_FALSE(metricProducer1_1->isActive());
-//
-// // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-// // same config.
-// long timeBase2 = 1000;
-// sp<StatsLogProcessor> processor2 =
-// CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor2->mMetricsManagers.size());
-// it = processor2->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-// auto& metricsManager2 = it->second;
-// EXPECT_TRUE(metricsManager2->isActive());
-//
-// EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
-// // We assume that the index of a MetricProducer within the mAllMetricProducers
-// // array follows the order in which metrics are added to the config.
-// auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
-// EXPECT_FALSE(metricProducer2_1->isActive());
-//
-// auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
-// EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
-// EXPECT_TRUE(metricProducer2_2->isActive());
-//
-// EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
-// // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-// // that matchers are indexed in the order that they are added to the config.
-// const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
-// EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
-// EXPECT_EQ(0, activation2_1_1->start_ns);
-// EXPECT_EQ(kNotActive, activation2_1_1->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
-//
-// const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
-// EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
-// EXPECT_EQ(0, activation2_1_2->start_ns);
-// EXPECT_EQ(kNotActive, activation2_1_2->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
-// // }}}-----------------------------------------------------------------------------------
-//
-// // Load saved state from disk.
-// processor2->LoadActiveConfigsFromDisk();
-//
-// // Metric 1 active; Activation 1 is active, Activation 2 is not active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer2_1->isActive());
-// int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
-// EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
-// EXPECT_EQ(kActive, activation2_1_1->state);
-// EXPECT_EQ(0, activation2_1_2->start_ns);
-// EXPECT_EQ(kNotActive, activation2_1_2->state);
-//
-// EXPECT_TRUE(metricProducer2_2->isActive());
-// // }}}--------------------------------------------------------------------------------
-//
-// // Trigger Activation 2 for Metric 1.
-// auto screenOnEvent = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_ON,
-// timeBase2 + 200
-// );
-// processor2->OnLogEvent(screenOnEvent.get());
-//
-// // Metric 1 active; Activation 1 is active, Activation 2 is active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer2_1->isActive());
-// EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
-// EXPECT_EQ(kActive, activation2_1_1->state);
-// EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
-// EXPECT_EQ(kActive, activation2_1_2->state);
-//
-// EXPECT_TRUE(metricProducer2_2->isActive());
-// // }}}---------------------------------------------------------------------------
-//
-// // Simulate shutdown by saving state to disk
-// shutDownTime = timeBase2 + 50 * NS_PER_SEC;
-// processor2->SaveActiveConfigsToDisk(shutDownTime);
-// EXPECT_TRUE(metricProducer2_1->isActive());
-// EXPECT_TRUE(metricProducer2_2->isActive());
-// ttl1 -= shutDownTime - timeBase2;
-// int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC
-// - (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
-//
-// // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-// // same config.
-// long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
-// sp<StatsLogProcessor> processor3 =
-// CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
-//
-// // Metric 1 is not active.
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor3->mMetricsManagers.size());
-// it = processor3->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor3->mMetricsManagers.end());
-// auto& metricsManager3 = it->second;
-// EXPECT_TRUE(metricsManager3->isActive());
-//
-// EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
-// // We assume that the index of a MetricProducer within the mAllMetricProducers
-// // array follows the order in which metrics are added to the config.
-// auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
-// EXPECT_FALSE(metricProducer3_1->isActive());
-//
-// auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
-// EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
-// EXPECT_TRUE(metricProducer3_2->isActive());
-//
-// EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
-// // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-// // that matchers are indexed in the order that they are added to the config.
-// const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
-// EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
-// EXPECT_EQ(0, activation3_1_1->start_ns);
-// EXPECT_EQ(kNotActive, activation3_1_1->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
-//
-// const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
-// EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
-// EXPECT_EQ(0, activation3_1_2->start_ns);
-// EXPECT_EQ(kNotActive, activation3_1_2->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
-// // }}}----------------------------------------------------------------------------------
-//
-// // Load saved state from disk.
-// processor3->LoadActiveConfigsFromDisk();
-//
-// // Metric 1 active: Activation 1 is active, Activation 2 is active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer3_1->isActive());
-// EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
-// EXPECT_EQ(kActive, activation3_1_1->state);
-// EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
-// EXPECT_EQ(kActive, activation3_1_2->state);
-//
-// EXPECT_TRUE(metricProducer3_2->isActive());
-// // }}}-------------------------------------------------------------------------------
-//
-//
-// // Trigger Activation 2 for Metric 1 again.
-// screenOnEvent = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_ON,
-// timeBase3 + 100 * NS_PER_SEC
-// );
-// processor3->OnLogEvent(screenOnEvent.get());
-//
-// // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
-// // Activation 2 is set to active
-// // Metric 2 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_TRUE(metricProducer3_1->isActive());
-// EXPECT_EQ(kNotActive, activation3_1_1->state);
-// EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
-// EXPECT_EQ(kActive, activation3_1_2->state);
-//
-// EXPECT_TRUE(metricProducer3_2->isActive());
-// // }}}---------------------------------------------------------------------------
-//}
-//
-//TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
-// int uid = 9876;
-// long configId = 12341;
-//
-// // Create config with 3 metrics:
-// // Metric 1: Activate on 2 activations, 1 on boot, 1 immediate.
-// // Metric 2: Activate on 2 activations, 1 on boot, 1 immediate.
-// // Metric 3: Always active
-// StatsdConfig config1;
-// config1.set_id(configId);
-// config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto jobStartMatcher = CreateStartScheduledJobAtomMatcher();
-// auto jobFinishMatcher = CreateFinishScheduledJobAtomMatcher();
-// *config1.add_atom_matcher() = wakelockAcquireMatcher;
-// *config1.add_atom_matcher() = screenOnMatcher;
-// *config1.add_atom_matcher() = jobStartMatcher;
-// *config1.add_atom_matcher() = jobFinishMatcher;
-//
-// long metricId1 = 1234561;
-// long metricId2 = 1234562;
-// long metricId3 = 1234563;
-//
-// auto countMetric1 = config1.add_count_metric();
-// countMetric1->set_id(metricId1);
-// countMetric1->set_what(wakelockAcquireMatcher.id());
-// countMetric1->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric2 = config1.add_count_metric();
-// countMetric2->set_id(metricId2);
-// countMetric2->set_what(wakelockAcquireMatcher.id());
-// countMetric2->set_bucket(FIVE_MINUTES);
-//
-// auto countMetric3 = config1.add_count_metric();
-// countMetric3->set_id(metricId3);
-// countMetric3->set_what(wakelockAcquireMatcher.id());
-// countMetric3->set_bucket(FIVE_MINUTES);
-//
-// // Metric 1 activates on boot for wakelock acquire, immediately for screen on.
-// auto metric1Activation = config1.add_metric_activation();
-// metric1Activation->set_metric_id(metricId1);
-// auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-// metric1ActivationTrigger1->set_ttl_seconds(100);
-// metric1ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
-// auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-// metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-// metric1ActivationTrigger2->set_ttl_seconds(200);
-// metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-//
-// // Metric 2 activates on boot for scheduled job start, immediately for scheduled job finish.
-// auto metric2Activation = config1.add_metric_activation();
-// metric2Activation->set_metric_id(metricId2);
-// auto metric2ActivationTrigger1 = metric2Activation->add_event_activation();
-// metric2ActivationTrigger1->set_atom_matcher_id(jobStartMatcher.id());
-// metric2ActivationTrigger1->set_ttl_seconds(100);
-// metric2ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
-// auto metric2ActivationTrigger2 = metric2Activation->add_event_activation();
-// metric2ActivationTrigger2->set_atom_matcher_id(jobFinishMatcher.id());
-// metric2ActivationTrigger2->set_ttl_seconds(200);
-// metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-//
-// // Send the config.
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// string serialized = config1.SerializeAsString();
-// service->addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
-//
-// // Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
-// StatsdConfig tmpConfig;
-// ConfigKey cfgKey1(uid, configId);
-// EXPECT_TRUE(StorageManager::readConfigFromDisk(cfgKey1, &tmpConfig));
-//
-// // Metric 1 is not active.
-// // Metric 2 is not active.
-// // Metric 3 is active.
-// // {{{---------------------------------------------------------------------------
-// sp<StatsLogProcessor> processor = service->mProcessor;
-// EXPECT_EQ(1, processor->mMetricsManagers.size());
-// auto it = processor->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor->mMetricsManagers.end());
-// auto& metricsManager1 = it->second;
-// EXPECT_TRUE(metricsManager1->isActive());
-// EXPECT_EQ(3, metricsManager1->mAllMetricProducers.size());
-//
-// auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
-// EXPECT_EQ(metricId1, metricProducer1->getMetricId());
-// EXPECT_FALSE(metricProducer1->isActive());
-//
-// auto& metricProducer2 = metricsManager1->mAllMetricProducers[1];
-// EXPECT_EQ(metricId2, metricProducer2->getMetricId());
-// EXPECT_FALSE(metricProducer2->isActive());
-//
-// auto& metricProducer3 = metricsManager1->mAllMetricProducers[2];
-// EXPECT_EQ(metricId3, metricProducer3->getMetricId());
-// EXPECT_TRUE(metricProducer3->isActive());
-//
-// // Check event activations.
-// EXPECT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
-// EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(),
-// metric1ActivationTrigger1->atom_matcher_id());
-// const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kNotActive, activation1->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
-//
-// EXPECT_EQ(metricsManager1->mAllAtomMatchers[1]->getId(),
-// metric1ActivationTrigger2->atom_matcher_id());
-// const auto& activation2 = metricProducer1->mEventActivationMap.at(1);
-// EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
-// EXPECT_EQ(0, activation2->start_ns);
-// EXPECT_EQ(kNotActive, activation2->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
-//
-// EXPECT_EQ(metricsManager1->mAllAtomMatchers[2]->getId(),
-// metric2ActivationTrigger1->atom_matcher_id());
-// const auto& activation3 = metricProducer2->mEventActivationMap.at(2);
-// EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns);
-// EXPECT_EQ(0, activation3->start_ns);
-// EXPECT_EQ(kNotActive, activation3->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType);
-//
-// EXPECT_EQ(metricsManager1->mAllAtomMatchers[3]->getId(),
-// metric2ActivationTrigger2->atom_matcher_id());
-// const auto& activation4 = metricProducer2->mEventActivationMap.at(3);
-// EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns);
-// EXPECT_EQ(0, activation4->start_ns);
-// EXPECT_EQ(kNotActive, activation4->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation4->activationType);
-// // }}}------------------------------------------------------------------------------
-//
-// // Trigger Activation 1 for Metric 1. Should activate on boot.
-// // Trigger Activation 4 for Metric 2. Should activate immediately.
-// long configAddedTimeNs = metricsManager1->mLastReportTimeNs;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 1 + configAddedTimeNs);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateFinishScheduledJobEvent(attributions1, "finish1", 2 + configAddedTimeNs);
-// processor->OnLogEvent(event.get());
-//
-// // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-// // Metric 2 is active. Activation 4 set to kActive
-// // Metric 3 is active.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_FALSE(metricProducer1->isActive());
-// EXPECT_EQ(0, activation1->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1->state);
-// EXPECT_EQ(0, activation2->start_ns);
-// EXPECT_EQ(kNotActive, activation2->state);
-//
-// EXPECT_TRUE(metricProducer2->isActive());
-// EXPECT_EQ(0, activation3->start_ns);
-// EXPECT_EQ(kNotActive, activation3->state);
-// EXPECT_EQ(2 + configAddedTimeNs, activation4->start_ns);
-// EXPECT_EQ(kActive, activation4->state);
-//
-// EXPECT_TRUE(metricProducer3->isActive());
-// // }}}-----------------------------------------------------------------------------
-//
-// // Can't fake time with StatsService.
-// // Lets get a time close to the system server death time and make sure it's sane.
-// int64_t approximateSystemServerDeath = getElapsedRealtimeNs();
-// EXPECT_TRUE(approximateSystemServerDeath > 2 + configAddedTimeNs);
-// EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
-//
-// // System server dies.
-// service->statsCompanionServiceDiedImpl();
-//
-// // We should have a new metrics manager. Lets get it and ensure activation status is restored.
-// // {{{---------------------------------------------------------------------------
-// EXPECT_EQ(1, processor->mMetricsManagers.size());
-// it = processor->mMetricsManagers.find(cfgKey1);
-// EXPECT_TRUE(it != processor->mMetricsManagers.end());
-// auto& metricsManager2 = it->second;
-// EXPECT_TRUE(metricsManager2->isActive());
-// EXPECT_EQ(3, metricsManager2->mAllMetricProducers.size());
-//
-// auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
-// EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
-// EXPECT_FALSE(metricProducer1001->isActive());
-//
-// auto& metricProducer1002 = metricsManager2->mAllMetricProducers[1];
-// EXPECT_EQ(metricId2, metricProducer1002->getMetricId());
-// EXPECT_TRUE(metricProducer1002->isActive());
-//
-// auto& metricProducer1003 = metricsManager2->mAllMetricProducers[2];
-// EXPECT_EQ(metricId3, metricProducer1003->getMetricId());
-// EXPECT_TRUE(metricProducer1003->isActive());
-//
-// // Check event activations.
-// // Activation 1 is kActiveOnBoot.
-// // Activation 2 and 3 are not active.
-// // Activation 4 is active.
-// EXPECT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
-// EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(),
-// metric1ActivationTrigger1->atom_matcher_id());
-// const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
-// EXPECT_EQ(0, activation1001->start_ns);
-// EXPECT_EQ(kActiveOnBoot, activation1001->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType);
-//
-// EXPECT_EQ(metricsManager2->mAllAtomMatchers[1]->getId(),
-// metric1ActivationTrigger2->atom_matcher_id());
-// const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1);
-// EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns);
-// EXPECT_EQ(0, activation1002->start_ns);
-// EXPECT_EQ(kNotActive, activation1002->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType);
-//
-// EXPECT_EQ(metricsManager2->mAllAtomMatchers[2]->getId(),
-// metric2ActivationTrigger1->atom_matcher_id());
-// const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2);
-// EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
-// EXPECT_EQ(0, activation1003->start_ns);
-// EXPECT_EQ(kNotActive, activation1003->state);
-// EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType);
-//
-// EXPECT_EQ(metricsManager2->mAllAtomMatchers[3]->getId(),
-// metric2ActivationTrigger2->atom_matcher_id());
-// const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3);
-// EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns);
-// EXPECT_EQ(2 + configAddedTimeNs, activation1004->start_ns);
-// EXPECT_EQ(kActive, activation1004->state);
-// EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
-// // }}}------------------------------------------------------------------------------
-//
-// // Clear the data stored on disk as a result of the system server death.
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer);
-//}
+TEST(StatsLogProcessorTest, TestOnDumpReportEraseData) {
+ // Setup a simple config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = wakelockAcquireMatcher;
+
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(123456);
+ countMetric->set_what(wakelockAcquireMatcher.id());
+ countMetric->set_bucket(FIVE_MINUTES);
+
+ ConfigKey cfgKey;
+ sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
+
+ std::vector<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event =
+ CreateAcquireWakelockEvent(2 /*timestamp*/, attributionUids, attributionTags, "wl1");
+ processor->OnLogEvent(event.get());
+
+ vector<uint8_t> bytes;
+ ConfigMetricsReportList output;
+
+ // Dump report WITHOUT erasing data.
+ processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST,
+ &bytes);
+ output.ParseFromArray(bytes.data(), bytes.size());
+ EXPECT_EQ(output.reports_size(), 1);
+ EXPECT_EQ(output.reports(0).metrics_size(), 1);
+ EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
+
+ // Dump report WITH erasing data. There should be data since we didn't previously erase it.
+ processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
+ output.ParseFromArray(bytes.data(), bytes.size());
+ EXPECT_EQ(output.reports_size(), 1);
+ EXPECT_EQ(output.reports(0).metrics_size(), 1);
+ EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
+
+ // Dump report again. There should be no data since we erased it.
+ processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
+ output.ParseFromArray(bytes.data(), bytes.size());
+ // We don't care whether statsd has a report, as long as it has no count metrics in it.
+ bool noData = output.reports_size() == 0 || output.reports(0).metrics_size() == 0 ||
+ output.reports(0).metrics(0).count_metrics().data_size() == 0;
+ EXPECT_TRUE(noData);
+}
+
+TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
+ int uid = 1111;
+
+ // Setup a simple config, no activation
+ StatsdConfig config1;
+ 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;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ ConfigKey cfgKey1(uid, cfgId1);
+
+ // Add another config, with two metrics, one with activation
+ StatsdConfig config2;
+ 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;
+
+ long metricId3 = 1234561;
+ long metricId4 = 1234562;
+
+ auto countMetric3 = config2.add_count_metric();
+ countMetric3->set_id(metricId3);
+ countMetric3->set_what(wakelockAcquireMatcher.id());
+ countMetric3->set_bucket(FIVE_MINUTES);
+
+ auto countMetric4 = config2.add_count_metric();
+ countMetric4->set_id(metricId4);
+ countMetric4->set_what(wakelockAcquireMatcher.id());
+ countMetric4->set_bucket(FIVE_MINUTES);
+
+ auto metric3Activation = config2.add_metric_activation();
+ metric3Activation->set_metric_id(metricId3);
+ metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto metric3ActivationTrigger = metric3Activation->add_event_activation();
+ metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric3ActivationTrigger->set_ttl_seconds(100);
+
+ ConfigKey cfgKey2(uid, cfgId2);
+
+ // Add another config, with two metrics, both with activations
+ StatsdConfig config3;
+ 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;
+
+ long metricId5 = 1234565;
+ long metricId6 = 1234566;
+ auto countMetric5 = config3.add_count_metric();
+ countMetric5->set_id(metricId5);
+ countMetric5->set_what(wakelockAcquireMatcher.id());
+ countMetric5->set_bucket(FIVE_MINUTES);
+
+ auto countMetric6 = config3.add_count_metric();
+ countMetric6->set_id(metricId6);
+ countMetric6->set_what(wakelockAcquireMatcher.id());
+ countMetric6->set_bucket(FIVE_MINUTES);
+
+ auto metric5Activation = config3.add_metric_activation();
+ metric5Activation->set_metric_id(metricId5);
+ metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto metric5ActivationTrigger = metric5Activation->add_event_activation();
+ metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric5ActivationTrigger->set_ttl_seconds(100);
+
+ auto metric6Activation = config3.add_metric_activation();
+ metric6Activation->set_metric_id(metricId6);
+ metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto metric6ActivationTrigger = metric6Activation->add_event_activation();
+ metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric6ActivationTrigger->set_ttl_seconds(200);
+
+ ConfigKey cfgKey3(uid, cfgId3);
+
+ 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, 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());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_TRUE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ // 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());
+
+ metricIt = metricsManager2->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId3) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
+ auto& metricProducer3 = *metricIt;
+ EXPECT_FALSE(metricProducer3->isActive());
+
+ metricIt = metricsManager2->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId4) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
+ auto& metricProducer4 = *metricIt;
+ EXPECT_TRUE(metricProducer4->isActive());
+
+ // 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());
+
+ metricIt = metricsManager3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId5) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
+ auto& metricProducer5 = *metricIt;
+ EXPECT_FALSE(metricProducer5->isActive());
+
+ metricIt = metricsManager3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId6) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
+ 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<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event =
+ CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
+ 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;
+ processor.SaveActiveConfigsToDisk(shutDownTime);
+ const int64_t ttl3 = event->GetElapsedTimestampNs() +
+ metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ const int64_t ttl5 = event->GetElapsedTimestampNs() +
+ metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ const int64_t ttl6 = event->GetElapsedTimestampNs() +
+ metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
+
+ // Create a second StatsLogProcessor and push the same 3 configs.
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+ processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
+ 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;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_TRUE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ // 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;
+ EXPECT_TRUE(metricsManager1002->isActive());
+
+ metricIt = metricsManager1002->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId3) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
+ auto& metricProducer1003 = *metricIt;
+ EXPECT_FALSE(metricProducer1003->isActive());
+
+ metricIt = metricsManager1002->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId4) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
+ 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;
+ EXPECT_FALSE(metricsManager1003->isActive());
+ EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size());
+
+ metricIt = metricsManager1003->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId5) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
+ auto& metricProducer1005 = *metricIt;
+ EXPECT_FALSE(metricProducer1005->isActive());
+
+ metricIt = metricsManager1003->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId6) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
+ 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);
+ EXPECT_EQ(0, activation1003->start_ns);
+ EXPECT_FALSE(metricProducer1005->isActive());
+ const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
+ EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns);
+ EXPECT_EQ(0, activation1005->start_ns);
+ EXPECT_FALSE(metricProducer1006->isActive());
+ const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
+ EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns);
+ EXPECT_EQ(0, activation1006->start_ns);
+
+ processor2->LoadActiveConfigsFromDisk();
+
+ // After loading activations from disk, assert that all 3 metrics are active.
+ EXPECT_TRUE(metricProducer1003->isActive());
+ EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
+ EXPECT_TRUE(metricProducer1005->isActive());
+ EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
+ EXPECT_TRUE(metricProducer1006->isActive());
+ EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
+
+ // Make sure no more broadcasts have happened.
+ EXPECT_EQ(broadcastCount, 1);
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBoot) {
+ int uid = 1111;
+
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger = metric1Activation->add_event_activation();
+ metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger->set_ttl_seconds(100);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
+ EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kNotActive, activation1->state);
+
+ std::vector<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event =
+ CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
+ processor->OnLogEvent(event.get());
+
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1->state);
+
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+ processor->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1->isActive());
+ const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
+
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager1001 = it->second;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
+ EXPECT_EQ(0, activation1001->start_ns);
+ EXPECT_EQ(kNotActive, activation1001->state);
+
+ processor2->LoadActiveConfigsFromDisk();
+
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
+ EXPECT_EQ(kActive, activation1001->state);
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
+ int uid = 1111;
+
+ // Create config with 2 metrics:
+ // Metric 1: Activate on boot with 2 activations
+ // Metric 2: Always active
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+ *config1.add_atom_matcher() = screenOnMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger1->set_ttl_seconds(100);
+ auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
+ metric1ActivationTrigger2->set_ttl_seconds(200);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ int i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kNotActive, activation1->state);
+
+ i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+ // }}}------------------------------------------------------------------------------
+
+ // Trigger Activation 1 for Metric 1
+ std::vector<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event =
+ CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
+ processor->OnLogEvent(event.get());
+
+ // Metric 1 is not active; Activation 1 set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1->state);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+
+ EXPECT_TRUE(metricProducer2->isActive());
+ // }}}-----------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+ processor->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager1001 = it->second;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
+ EXPECT_EQ(0, activation1001_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_1->state);
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+ // }}}-----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor2->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}--------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1.
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
+ processor2->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ shutDownTime = timeBase2 + 50 * NS_PER_SEC;
+ processor2->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_TRUE(metricProducer1002->isActive());
+ ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor3 =
+ CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ it = processor3->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor3->mMetricsManagers.end());
+ auto& metricsManagerTimeBase3 = it->second;
+ EXPECT_TRUE(metricsManagerTimeBase3->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_1 = *metricIt;
+ EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_2 = *metricIt;
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor3->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1 again.
+ screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
+ android::view::DISPLAY_STATE_ON);
+ processor3->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk.
+ shutDownTime = timeBase3 + 500 * NS_PER_SEC;
+ processor3->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_TRUE(metricProducer1002->isActive());
+ ttl1 = timeBase3 + ttl1 - shutDownTime;
+ ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor4 =
+ CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor4->mMetricsManagers.size());
+ it = processor4->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor4->mMetricsManagers.end());
+ auto& metricsManagerTimeBase4 = it->second;
+ EXPECT_TRUE(metricsManagerTimeBase4->isActive());
+
+ metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
+ auto& metricProducerTimeBase4_1 = *metricIt;
+ EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
+
+ metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
+ auto& metricProducerTimeBase4_2 = *metricIt;
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+
+ i = 0;
+ for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase4_1->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
+
+ i = 0;
+ for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase4_2->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor4->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is not active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
+ EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
+ EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
+ int uid = 1111;
+
+ // Create config with 2 metrics:
+ // Metric 1: Activate on boot with 2 activations
+ // Metric 2: Always active
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+ *config1.add_atom_matcher() = screenOnMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger1->set_ttl_seconds(100);
+ auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
+ metric1ActivationTrigger2->set_ttl_seconds(200);
+ metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor1 =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor1->mMetricsManagers.size());
+ auto it = processor1->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor1->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
+
+ auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer1_2->isActive());
+
+ EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
+
+ const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
+ // }}}------------------------------------------------------------------------------
+
+ // Trigger Activation 1 for Metric 1
+ std::vector<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event =
+ CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
+ processor1->OnLogEvent(event.get());
+
+ // Metric 1 is not active; Activation 1 set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducer1_1->isActive());
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
+
+ EXPECT_TRUE(metricProducer1_2->isActive());
+ // }}}-----------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+ processor1->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1_1->isActive());
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager2 = it->second;
+ EXPECT_TRUE(metricsManager2->isActive());
+
+ EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer2_1->isActive());
+
+ auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer2_2->isActive());
+
+ EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
+ EXPECT_EQ(0, activation2_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
+
+ const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
+ // }}}-----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor2->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
+
+ EXPECT_TRUE(metricProducer2_2->isActive());
+ // }}}--------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1.
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
+ processor2->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
+ EXPECT_EQ(kActive, activation2_1_2->state);
+
+ EXPECT_TRUE(metricProducer2_2->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ shutDownTime = timeBase2 + 50 * NS_PER_SEC;
+ processor2->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
+ ttl1 -= shutDownTime - timeBase2;
+ int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC -
+ (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor3 =
+ CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ it = processor3->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor3->mMetricsManagers.end());
+ auto& metricsManager3 = it->second;
+ EXPECT_TRUE(metricsManager3->isActive());
+
+ EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer3_1->isActive());
+
+ auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer3_2->isActive());
+
+ EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
+ EXPECT_EQ(0, activation3_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
+
+ const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
+ EXPECT_EQ(0, activation3_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor3->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
+ EXPECT_EQ(kActive, activation3_1_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
+
+ EXPECT_TRUE(metricProducer3_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1 again.
+ screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
+ android::view::DISPLAY_STATE_ON);
+ processor3->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
+ // Activation 2 is set to active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
+
+ EXPECT_TRUE(metricProducer3_2->isActive());
+ // }}}---------------------------------------------------------------------------
+}
+
+TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
+ int uid = 9876;
+ long configId = 12341;
+
+ // Create config with 3 metrics:
+ // Metric 1: Activate on 2 activations, 1 on boot, 1 immediate.
+ // Metric 2: Activate on 2 activations, 1 on boot, 1 immediate.
+ // Metric 3: Always active
+ StatsdConfig config1;
+ config1.set_id(configId);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto jobStartMatcher = CreateStartScheduledJobAtomMatcher();
+ auto jobFinishMatcher = CreateFinishScheduledJobAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+ *config1.add_atom_matcher() = screenOnMatcher;
+ *config1.add_atom_matcher() = jobStartMatcher;
+ *config1.add_atom_matcher() = jobFinishMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+ long metricId3 = 1234563;
+
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto countMetric3 = config1.add_count_metric();
+ countMetric3->set_id(metricId3);
+ countMetric3->set_what(wakelockAcquireMatcher.id());
+ countMetric3->set_bucket(FIVE_MINUTES);
+
+ // Metric 1 activates on boot for wakelock acquire, immediately for screen on.
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger1->set_ttl_seconds(100);
+ metric1ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
+ metric1ActivationTrigger2->set_ttl_seconds(200);
+ metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
+
+ // Metric 2 activates on boot for scheduled job start, immediately for scheduled job finish.
+ auto metric2Activation = config1.add_metric_activation();
+ metric2Activation->set_metric_id(metricId2);
+ auto metric2ActivationTrigger1 = metric2Activation->add_event_activation();
+ metric2ActivationTrigger1->set_atom_matcher_id(jobStartMatcher.id());
+ metric2ActivationTrigger1->set_ttl_seconds(100);
+ metric2ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric2ActivationTrigger2 = metric2Activation->add_event_activation();
+ metric2ActivationTrigger2->set_atom_matcher_id(jobFinishMatcher.id());
+ metric2ActivationTrigger2->set_ttl_seconds(200);
+ metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
+
+ // Send the config.
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ string serialized = config1.SerializeAsString();
+ service->addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
+
+ // Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
+ StatsdConfig tmpConfig;
+ ConfigKey cfgKey1(uid, configId);
+ EXPECT_TRUE(StorageManager::readConfigFromDisk(cfgKey1, &tmpConfig));
+
+ // Metric 1 is not active.
+ // Metric 2 is not active.
+ // Metric 3 is active.
+ // {{{---------------------------------------------------------------------------
+ sp<StatsLogProcessor> processor = service->mProcessor;
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+ EXPECT_EQ(3, metricsManager1->mAllMetricProducers.size());
+
+ auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
+ EXPECT_EQ(metricId1, metricProducer1->getMetricId());
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ auto& metricProducer2 = metricsManager1->mAllMetricProducers[1];
+ EXPECT_EQ(metricId2, metricProducer2->getMetricId());
+ EXPECT_FALSE(metricProducer2->isActive());
+
+ auto& metricProducer3 = metricsManager1->mAllMetricProducers[2];
+ EXPECT_EQ(metricId3, metricProducer3->getMetricId());
+ EXPECT_TRUE(metricProducer3->isActive());
+
+ // Check event activations.
+ EXPECT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
+ EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(),
+ metric1ActivationTrigger1->atom_matcher_id());
+ const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kNotActive, activation1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
+
+ EXPECT_EQ(metricsManager1->mAllAtomMatchers[1]->getId(),
+ metric1ActivationTrigger2->atom_matcher_id());
+ const auto& activation2 = metricProducer1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
+
+ EXPECT_EQ(metricsManager1->mAllAtomMatchers[2]->getId(),
+ metric2ActivationTrigger1->atom_matcher_id());
+ const auto& activation3 = metricProducer2->mEventActivationMap.at(2);
+ EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns);
+ EXPECT_EQ(0, activation3->start_ns);
+ EXPECT_EQ(kNotActive, activation3->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType);
+
+ EXPECT_EQ(metricsManager1->mAllAtomMatchers[3]->getId(),
+ metric2ActivationTrigger2->atom_matcher_id());
+ const auto& activation4 = metricProducer2->mEventActivationMap.at(3);
+ EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns);
+ EXPECT_EQ(0, activation4->start_ns);
+ EXPECT_EQ(kNotActive, activation4->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation4->activationType);
+ // }}}------------------------------------------------------------------------------
+
+ // Trigger Activation 1 for Metric 1. Should activate on boot.
+ // Trigger Activation 4 for Metric 2. Should activate immediately.
+ long configAddedTimeNs = metricsManager1->mLastReportTimeNs;
+ std::vector<int> attributionUids = {111};
+ std::vector<string> attributionTags = {"App1"};
+ std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(
+ 1 + configAddedTimeNs, attributionUids, attributionTags, "wl1");
+ processor->OnLogEvent(event1.get());
+
+ std::unique_ptr<LogEvent> event2 = CreateFinishScheduledJobEvent(
+ 2 + configAddedTimeNs, attributionUids, attributionTags, "finish1");
+ processor->OnLogEvent(event2.get());
+
+ // Metric 1 is not active; Activation 1 set to kActiveOnBoot
+ // Metric 2 is active. Activation 4 set to kActive
+ // Metric 3 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1->state);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+
+ EXPECT_TRUE(metricProducer2->isActive());
+ EXPECT_EQ(0, activation3->start_ns);
+ EXPECT_EQ(kNotActive, activation3->state);
+ EXPECT_EQ(2 + configAddedTimeNs, activation4->start_ns);
+ EXPECT_EQ(kActive, activation4->state);
+
+ EXPECT_TRUE(metricProducer3->isActive());
+ // }}}-----------------------------------------------------------------------------
+
+ // Can't fake time with StatsService.
+ // Lets get a time close to the system server death time and make sure it's sane.
+ int64_t approximateSystemServerDeath = getElapsedRealtimeNs();
+ EXPECT_TRUE(approximateSystemServerDeath > 2 + configAddedTimeNs);
+ EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
+
+ // System server dies.
+ service->statsCompanionServiceDiedImpl();
+
+ // We should have a new metrics manager. Lets get it and ensure activation status is restored.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager2 = it->second;
+ EXPECT_TRUE(metricsManager2->isActive());
+ EXPECT_EQ(3, metricsManager2->mAllMetricProducers.size());
+
+ auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
+ EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ auto& metricProducer1002 = metricsManager2->mAllMetricProducers[1];
+ EXPECT_EQ(metricId2, metricProducer1002->getMetricId());
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ auto& metricProducer1003 = metricsManager2->mAllMetricProducers[2];
+ EXPECT_EQ(metricId3, metricProducer1003->getMetricId());
+ EXPECT_TRUE(metricProducer1003->isActive());
+
+ // Check event activations.
+ // Activation 1 is kActiveOnBoot.
+ // Activation 2 and 3 are not active.
+ // Activation 4 is active.
+ EXPECT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
+ EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(),
+ metric1ActivationTrigger1->atom_matcher_id());
+ const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
+ EXPECT_EQ(0, activation1001->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1001->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType);
+
+ EXPECT_EQ(metricsManager2->mAllAtomMatchers[1]->getId(),
+ metric1ActivationTrigger2->atom_matcher_id());
+ const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns);
+ EXPECT_EQ(0, activation1002->start_ns);
+ EXPECT_EQ(kNotActive, activation1002->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType);
+
+ EXPECT_EQ(metricsManager2->mAllAtomMatchers[2]->getId(),
+ metric2ActivationTrigger1->atom_matcher_id());
+ const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
+ EXPECT_EQ(0, activation1003->start_ns);
+ EXPECT_EQ(kNotActive, activation1003->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType);
+
+ EXPECT_EQ(metricsManager2->mAllAtomMatchers[3]->getId(),
+ metric2ActivationTrigger2->atom_matcher_id());
+ const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns);
+ EXPECT_EQ(2 + configAddedTimeNs, activation1004->start_ns);
+ EXPECT_EQ(kActive, activation1004->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
+ // }}}------------------------------------------------------------------------------
+
+ // Clear the data stored on disk as a result of the system server death.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true, ADB_DUMP, FAST,
+ &buffer);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index a49c18fb9857..29005a2070fe 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -39,35 +39,28 @@ using android::util::ProtoReader;
const string kApp1 = "app1.sharing.1";
const string kApp2 = "app2.sharing.1";
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(UidMapTest, TestIsolatedUID) {
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// // Construct the processor with a dummy sendBroadcast function that does nothing.
-// StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-// [](const ConfigKey& key) { return true; },
-// [](const int&, const vector<int64_t>&) {return true;});
-// LogEvent addEvent(util::ISOLATED_UID_CHANGED, 1);
-// addEvent.write(100); // parent UID
-// addEvent.write(101); // isolated UID
-// addEvent.write(1); // Indicates creation.
-// addEvent.init();
-//
-// EXPECT_EQ(101, m->getHostUidOrSelf(101));
-//
-// p.OnLogEvent(&addEvent);
-// EXPECT_EQ(100, m->getHostUidOrSelf(101));
-//
-// LogEvent removeEvent(util::ISOLATED_UID_CHANGED, 1);
-// removeEvent.write(100); // parent UID
-// removeEvent.write(101); // isolated UID
-// removeEvent.write(0); // Indicates removal.
-// removeEvent.init();
-// p.OnLogEvent(&removeEvent);
-// EXPECT_EQ(101, m->getHostUidOrSelf(101));
-//}
+TEST(UidMapTest, TestIsolatedUID) {
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ // Construct the processor with a dummy sendBroadcast function that does nothing.
+ StatsLogProcessor p(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+ [](const ConfigKey& key) { return true; },
+ [](const int&, const vector<int64_t>&) { return true; });
+
+ std::unique_ptr<LogEvent> addEvent = CreateIsolatedUidChangedEvent(
+ 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 1 /*is_create*/);
+ EXPECT_EQ(101, m->getHostUidOrSelf(101));
+ p.OnLogEvent(addEvent.get());
+ EXPECT_EQ(100, m->getHostUidOrSelf(101));
+
+ std::unique_ptr<LogEvent> removeEvent = CreateIsolatedUidChangedEvent(
+ 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 0 /*is_create*/);
+ p.OnLogEvent(removeEvent.get());
+ EXPECT_EQ(101, m->getHostUidOrSelf(101));
+}
TEST(UidMapTest, TestMatching) {
UidMap m;
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index 4c55683d909c..5eef92e12ba9 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -12,18 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gtest/gtest.h>
+#include "src/shell/ShellSubscriber.h"
+#include <gtest/gtest.h>
+#include <stdio.h>
#include <unistd.h>
+
+#include <vector>
+
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
#include "frameworks/base/cmds/statsd/src/shell/shell_data.pb.h"
-#include "src/shell/ShellSubscriber.h"
#include "stats_event.h"
#include "tests/metrics/metrics_test_helper.h"
-
-#include <stdio.h>
-#include <vector>
+#include "tests/statsd_test_util.h"
using namespace android::os::statsd;
using android::sp;
@@ -118,18 +120,9 @@ TEST(ShellSubscriberTest, testPushedSubscription) {
vector<std::shared_ptr<LogEvent>> pushedList;
// Create the LogEvent from an AStatsEvent
- AStatsEvent* statsEvent = AStatsEvent_obtain();
- AStatsEvent_setAtomId(statsEvent, 29 /*screen_state_atom_id*/);
- AStatsEvent_overwriteTimestamp(statsEvent, 1000);
- AStatsEvent_writeInt32(statsEvent, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
- AStatsEvent_build(statsEvent);
- size_t size;
- uint8_t* buffer = AStatsEvent_getBuffer(statsEvent, &size);
- std::shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
- logEvent->parseBuffer(buffer, size);
- AStatsEvent_release(statsEvent);
-
- pushedList.push_back(logEvent);
+ std::unique_ptr<LogEvent> logEvent = CreateScreenStateChangedEvent(
+ 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ pushedList.push_back(std::move(logEvent));
// create a simple config to get screen events
ShellSubscription config;
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index b1633c63028d..a0e00954531f 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <gtest/gtest.h>
-#include "state/StateManager.h"
#include "state/StateTracker.h"
-#include "state/StateListener.h"
+#include <gtest/gtest.h>
+
+#include "state/StateListener.h"
+#include "state/StateManager.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
#ifdef __ANDROID__
@@ -26,6 +28,8 @@ namespace android {
namespace os {
namespace statsd {
+const int32_t timestampNs = 1000;
+
/**
* Mock StateListener class for testing.
* Stores primary key and state pairs.
@@ -56,95 +60,49 @@ int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& query
return output.mValue.int_value;
}
-// TODO(b/149590301): Update these helpers to use new socket schema.
-//// START: build event functions.
-//// State with no primary fields - ScreenStateChanged
-//std::shared_ptr<LogEvent> buildScreenEvent(int state) {
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
-// event->write((int32_t)state);
-// event->init();
-// return event;
-//}
-//
-//// State with one primary field - UidProcessStateChanged
-//std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) {
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
-// event->write((int32_t)uid);
-// event->write((int32_t)state);
-// event->init();
-// return event;
-//}
-//
-//// State with first uid in attribution chain as primary field - WakelockStateChanged
-//std::shared_ptr<LogEvent> buildPartialWakelockEvent(int uid, const std::string& tag, bool acquire) {
-// std::vector<AttributionNodeInternal> chain;
-// chain.push_back(AttributionNodeInternal());
-// AttributionNodeInternal& attr = chain.back();
-// attr.set_uid(uid);
-//
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::WAKELOCK_STATE_CHANGED, 1000 /* timestamp */);
-// event->write(chain);
-// event->write((int32_t)1); // PARTIAL_WAKE_LOCK
-// event->write(tag);
-// event->write(acquire ? 1 : 0);
-// event->init();
-// return event;
-//}
-//
-//// State with multiple primary fields - OverlayStateChanged
-//std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) {
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
-// event->write((int32_t)uid);
-// event->write(packageName);
-// event->write(true); // using_alert_window
-// event->write((int32_t)state);
-// event->init();
-// return event;
-//}
-//
-//// Incorrect event - missing fields
-//std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) {
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
-// event->write((int32_t)uid);
-// event->write(packageName);
-// event->write((int32_t)state);
-// event->init();
-// return event;
-//}
-//
-//// Incorrect event - exclusive state has wrong type
-//std::shared_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::string& packageName) {
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
-// event->write((int32_t)uid);
-// event->write(packageName);
-// event->write(true);
-// event->write("string"); // exclusive state: string instead of int
-// event->init();
-// return event;
-//}
-//
-//std::shared_ptr<LogEvent> buildBleScanEvent(int uid, bool acquire, bool reset) {
-// std::vector<AttributionNodeInternal> chain;
-// chain.push_back(AttributionNodeInternal());
-// AttributionNodeInternal& attr = chain.back();
-// attr.set_uid(uid);
-//
-// std::shared_ptr<LogEvent> event =
-// std::make_shared<LogEvent>(util::BLE_SCAN_STATE_CHANGED, 1000);
-// event->write(chain);
-// event->write(reset ? 2 : acquire ? 1 : 0); // PARTIAL_WAKE_LOCK
-// event->write(0); // filtered
-// event->write(0); // first match
-// event->write(0); // opportunistic
-// event->init();
-// return event;
-//}
+// START: build event functions.
+// Incorrect event - missing fields
+std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName,
+ int state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, 1000);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, packageName.c_str());
+ // Missing field 3 - using_alert_window.
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+// Incorrect event - exclusive state has wrong type
+std::unique_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::string& packageName) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, 1000);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, packageName.c_str());
+ AStatsEvent_writeInt32(statsEvent, true); // using_alert_window
+ AStatsEvent_writeString(statsEvent, "string"); // exclusive state: string instead of int
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
// END: build event functions.
// START: get primary key functions
@@ -293,302 +251,323 @@ TEST(StateTrackerTest, TestUnregisterListener) {
EXPECT_EQ(0, mgr.getStateTrackersCount());
EXPECT_EQ(-1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
}
-// TODO(b/149590301): Update these tests to use new socket schema.
-///**
-// * Test a binary state atom with nested counting.
-// *
-// * To go from an "ON" state to an "OFF" state with nested counting, we must see
-// * an equal number of "OFF" events as "ON" events.
-// * For example, ACQUIRE, ACQUIRE, RELEASE will still be in the ACQUIRE state.
-// * ACQUIRE, ACQUIRE, RELEASE, RELEASE will be in the RELEASE state.
-// */
-//TEST(StateTrackerTest, TestStateChangeNested) {
-// sp<TestStateListener> listener = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener);
-//
-// std::shared_ptr<LogEvent> event1 =
-// buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/);
-// mgr.onLogEvent(*event1);
-// EXPECT_EQ(1, listener->updates.size());
-// EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(1, listener->updates[0].mState);
-// listener->updates.clear();
-//
-// std::shared_ptr<LogEvent> event2 =
-// buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/);
-// mgr.onLogEvent(*event2);
-// EXPECT_EQ(0, listener->updates.size());
-//
-// std::shared_ptr<LogEvent> event3 =
-// buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/);
-// mgr.onLogEvent(*event3);
-// EXPECT_EQ(0, listener->updates.size());
-//
-// std::shared_ptr<LogEvent> event4 =
-// buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/);
-// mgr.onLogEvent(*event4);
-// EXPECT_EQ(1, listener->updates.size());
-// EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(0, listener->updates[0].mState);
-//}
-//
-///**
-// * Test a state atom with a reset state.
-// *
-// * If the reset state value is seen, every state in the map is set to the default
-// * state and every listener is notified.
-// */
-//TEST(StateTrackerTest, TestStateChangeReset) {
-// sp<TestStateListener> listener = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::BLE_SCAN_STATE_CHANGED, listener);
-//
-// std::shared_ptr<LogEvent> event1 =
-// buildBleScanEvent(1000 /* uid */, true /*acquire*/, false /*reset*/);
-// mgr.onLogEvent(*event1);
-// EXPECT_EQ(1, listener->updates.size());
-// EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
-// listener->updates.clear();
-//
-// std::shared_ptr<LogEvent> event2 =
-// buildBleScanEvent(2000 /* uid */, true /*acquire*/, false /*reset*/);
-// mgr.onLogEvent(*event2);
-// EXPECT_EQ(1, listener->updates.size());
-// EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
-// listener->updates.clear();
-//
-// std::shared_ptr<LogEvent> event3 =
-// buildBleScanEvent(2000 /* uid */, false /*acquire*/, true /*reset*/);
-// mgr.onLogEvent(*event3);
-// EXPECT_EQ(2, listener->updates.size());
-// EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[0].mState);
-// EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[1].mState);
-//}
-//
-///**
-// * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
-// * updates listener for states without primary keys.
-// */
-//TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-//
-// // log event
-// std::shared_ptr<LogEvent> event =
-// buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-// mgr.onLogEvent(*event);
-//
-// // check listener was updated
-// EXPECT_EQ(1, listener1->updates.size());
-// EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
-// EXPECT_EQ(2, listener1->updates[0].mState);
-//
-// // check StateTracker was updated by querying for state
-// HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-//}
-//
-///**
-// * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
-// * updates listener for states with one primary key.
-// */
-//TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener1);
-//
-// // log event
-// std::shared_ptr<LogEvent> event =
-// buildUidProcessEvent(1000 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP);
-// mgr.onLogEvent(*event);
-//
-// // check listener was updated
-// EXPECT_EQ(1, listener1->updates.size());
-// EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(1002, listener1->updates[0].mState);
-//
-// // check StateTracker was updated by querying for state
-// HashableDimensionKey queryKey;
-// getUidProcessKey(1000 /* uid */, &queryKey);
-// EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey));
-//}
-//
-//TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener1);
-//
-// // Log event.
-// std::shared_ptr<LogEvent> event =
-// buildPartialWakelockEvent(1001 /* uid */, "tag1", true /* acquire */);
-// mgr.onLogEvent(*event);
-//
-// EXPECT_EQ(1, mgr.getStateTrackersCount());
-// EXPECT_EQ(1, mgr.getListenersCount(util::WAKELOCK_STATE_CHANGED));
-//
-// // Check listener was updated.
-// EXPECT_EQ(1, listener1->updates.size());
-// EXPECT_EQ(3, listener1->updates[0].mKey.getValues().size());
-// EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value);
-// EXPECT_EQ("tag1", listener1->updates[0].mKey.getValues()[2].mValue.str_value);
-// EXPECT_EQ(WakelockStateChanged::ACQUIRE, listener1->updates[0].mState);
-//
-// // Check StateTracker was updated by querying for state.
-// HashableDimensionKey queryKey;
-// getPartialWakelockKey(1001 /* uid */, "tag1", &queryKey);
-// EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-// getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey));
-//
-// // No state stored for this query key.
-// HashableDimensionKey queryKey2;
-// getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
-// EXPECT_EQ(WakelockStateChanged::RELEASE,
-// getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey2));
-//
-// // Partial query fails.
-// HashableDimensionKey queryKey3;
-// getPartialWakelockKey(1001 /* uid */, &queryKey3);
-// EXPECT_EQ(WakelockStateChanged::RELEASE,
-// getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey3));
-//}
-//
-///**
-// * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
-// * updates listener for states with multiple primary keys.
-// */
-//TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
-//
-// // log event
-// std::shared_ptr<LogEvent> event =
-// buildOverlayEvent(1000 /* uid */, "package1", 1); // state: ENTERED
-// mgr.onLogEvent(*event);
-//
-// // check listener was updated
-// EXPECT_EQ(1, listener1->updates.size());
-// EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-// EXPECT_EQ(1, listener1->updates[0].mState);
-//
-// // check StateTracker was updated by querying for state
-// HashableDimensionKey queryKey;
-// getOverlayKey(1000 /* uid */, "package1", &queryKey);
-// EXPECT_EQ(OverlayStateChanged::ENTERED,
-// getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey));
-//}
-//
-///**
-// * Test StateManager's onLogEvent and StateListener's onStateChanged
-// * when there is an error extracting state from log event. Listener is not
-// * updated of state change.
-// */
-//TEST(StateTrackerTest, TestStateChangeEventError) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
-//
-// // log event
-// std::shared_ptr<LogEvent> event1 =
-// buildIncorrectOverlayEvent(1000 /* uid */, "package1", 1 /* state */);
-// std::shared_ptr<LogEvent> event2 = buildOverlayEventBadStateType(1001 /* uid */, "package2");
-//
-// // check listener was updated
-// mgr.onLogEvent(*event1);
-// EXPECT_EQ(0, listener1->updates.size());
-// mgr.onLogEvent(*event2);
-// EXPECT_EQ(0, listener1->updates.size());
-//}
-//
-//TEST(StateTrackerTest, TestStateQuery) {
-// sp<TestStateListener> listener1 = new TestStateListener();
-// sp<TestStateListener> listener2 = new TestStateListener();
-// sp<TestStateListener> listener3 = new TestStateListener();
-// sp<TestStateListener> listener4 = new TestStateListener();
-// StateManager mgr;
-// mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-// mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener2);
-// mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener3);
-// mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener4);
-//
-// std::shared_ptr<LogEvent> event1 = buildUidProcessEvent(
-// 1000,
-// android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
-// std::shared_ptr<LogEvent> event2 = buildUidProcessEvent(
-// 1001,
-// android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE); // state value:
-// // 1003
-// std::shared_ptr<LogEvent> event3 = buildUidProcessEvent(
-// 1002,
-// android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT); // state value: 1000
-// std::shared_ptr<LogEvent> event4 = buildUidProcessEvent(
-// 1001,
-// android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
-// std::shared_ptr<LogEvent> event5 =
-// buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-// std::shared_ptr<LogEvent> event6 =
-// buildOverlayEvent(1000, "package1", OverlayStateChanged::ENTERED);
-// std::shared_ptr<LogEvent> event7 =
-// buildOverlayEvent(1000, "package2", OverlayStateChanged::EXITED);
-// std::shared_ptr<LogEvent> event8 = buildPartialWakelockEvent(1005, "tag1", true);
-// std::shared_ptr<LogEvent> event9 = buildPartialWakelockEvent(1005, "tag2", false);
-//
-// mgr.onLogEvent(*event1);
-// mgr.onLogEvent(*event2);
-// mgr.onLogEvent(*event3);
-// mgr.onLogEvent(*event5);
-// mgr.onLogEvent(*event5);
-// mgr.onLogEvent(*event6);
-// mgr.onLogEvent(*event7);
-// mgr.onLogEvent(*event8);
-// mgr.onLogEvent(*event9);
-//
-// // Query for UidProcessState of uid 1001
-// HashableDimensionKey queryKey1;
-// getUidProcessKey(1001, &queryKey1);
-// EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
-//
-// // Query for UidProcessState of uid 1004 - not in state map
-// HashableDimensionKey queryKey2;
-// getUidProcessKey(1004, &queryKey2);
-// EXPECT_EQ(-1, getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED,
-// queryKey2)); // default state
-//
-// // Query for UidProcessState of uid 1001 - after change in state
-// mgr.onLogEvent(*event4);
-// EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
-//
-// // Query for ScreenState
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// getStateInt(mgr, util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
-//
-// // Query for OverlayState of uid 1000, package name "package2"
-// HashableDimensionKey queryKey3;
-// getOverlayKey(1000, "package2", &queryKey3);
-// EXPECT_EQ(OverlayStateChanged::EXITED,
-// getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey3));
-//
-// // Query for WakelockState of uid 1005, tag 2
-// HashableDimensionKey queryKey4;
-// getPartialWakelockKey(1005, "tag2", &queryKey4);
-// EXPECT_EQ(WakelockStateChanged::RELEASE,
-// getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey4));
-//
-// // Query for WakelockState of uid 1005, tag 1
-// HashableDimensionKey queryKey5;
-// getPartialWakelockKey(1005, "tag1", &queryKey5);
-// EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-// getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey5));
-//}
+
+/**
+ * Test a binary state atom with nested counting.
+ *
+ * To go from an "ON" state to an "OFF" state with nested counting, we must see
+ * an equal number of "OFF" events as "ON" events.
+ * For example, ACQUIRE, ACQUIRE, RELEASE will still be in the ACQUIRE state.
+ * ACQUIRE, ACQUIRE, RELEASE, RELEASE will be in the RELEASE state.
+ */
+TEST(StateTrackerTest, TestStateChangeNested) {
+ sp<TestStateListener> listener = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener);
+
+ std::vector<int> attributionUids1 = {1000};
+ std::vector<string> attributionTags1 = {"tag"};
+
+ std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(timestampNs, attributionUids1,
+ attributionTags1, "wakelockName");
+ mgr.onLogEvent(*event1);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener->updates[0].mState);
+ listener->updates.clear();
+
+ std::unique_ptr<LogEvent> event2 = CreateAcquireWakelockEvent(
+ timestampNs + 1000, attributionUids1, attributionTags1, "wakelockName");
+ mgr.onLogEvent(*event2);
+ EXPECT_EQ(0, listener->updates.size());
+
+ std::unique_ptr<LogEvent> event3 = CreateReleaseWakelockEvent(
+ timestampNs + 2000, attributionUids1, attributionTags1, "wakelockName");
+ mgr.onLogEvent(*event3);
+ EXPECT_EQ(0, listener->updates.size());
+
+ std::unique_ptr<LogEvent> event4 = CreateReleaseWakelockEvent(
+ timestampNs + 3000, attributionUids1, attributionTags1, "wakelockName");
+ mgr.onLogEvent(*event4);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(0, listener->updates[0].mState);
+}
+
+/**
+ * Test a state atom with a reset state.
+ *
+ * If the reset state value is seen, every state in the map is set to the default
+ * state and every listener is notified.
+ */
+TEST(StateTrackerTest, TestStateChangeReset) {
+ sp<TestStateListener> listener = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::BLE_SCAN_STATE_CHANGED, listener);
+
+ std::vector<int> attributionUids1 = {1000};
+ std::vector<string> attributionTags1 = {"tag1"};
+ std::vector<int> attributionUids2 = {2000};
+
+ std::unique_ptr<LogEvent> event1 =
+ CreateBleScanStateChangedEvent(timestampNs, attributionUids1, attributionTags1,
+ BleScanStateChanged::ON, false, false, false);
+ mgr.onLogEvent(*event1);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
+ listener->updates.clear();
+
+ std::unique_ptr<LogEvent> event2 =
+ CreateBleScanStateChangedEvent(timestampNs + 1000, attributionUids2, attributionTags1,
+ BleScanStateChanged::ON, false, false, false);
+ mgr.onLogEvent(*event2);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
+ listener->updates.clear();
+
+ std::unique_ptr<LogEvent> event3 =
+ CreateBleScanStateChangedEvent(timestampNs + 2000, attributionUids2, attributionTags1,
+ BleScanStateChanged::RESET, false, false, false);
+ mgr.onLogEvent(*event3);
+ EXPECT_EQ(2, listener->updates.size());
+ EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[0].mState);
+ EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[1].mState);
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states without primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
+
+ // log event
+ std::unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
+ timestampNs, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
+ EXPECT_EQ(2, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states with one primary key.
+ */
+TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener1);
+
+ // log event
+ std::unique_ptr<LogEvent> event = CreateUidProcessStateChangedEvent(
+ timestampNs, 1000 /*uid*/, android::app::ProcessStateEnum::PROCESS_STATE_TOP);
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1002, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey;
+ getUidProcessKey(1000 /* uid */, &queryKey);
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey));
+}
+
+TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener1);
+
+ // Log event.
+ std::vector<int> attributionUids = {1001};
+ std::vector<string> attributionTags = {"tag1"};
+
+ std::unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timestampNs, attributionUids,
+ attributionTags, "wakelockName");
+ mgr.onLogEvent(*event);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(util::WAKELOCK_STATE_CHANGED));
+
+ // Check listener was updated.
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(3, listener1->updates[0].mKey.getValues().size());
+ EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value);
+ EXPECT_EQ("wakelockName", listener1->updates[0].mKey.getValues()[2].mValue.str_value);
+ EXPECT_EQ(WakelockStateChanged::ACQUIRE, listener1->updates[0].mState);
+
+ // Check StateTracker was updated by querying for state.
+ HashableDimensionKey queryKey;
+ getPartialWakelockKey(1001 /* uid */, "wakelockName", &queryKey);
+ EXPECT_EQ(WakelockStateChanged::ACQUIRE,
+ getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey));
+
+ // No state stored for this query key.
+ HashableDimensionKey queryKey2;
+ getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
+ EXPECT_EQ(WakelockStateChanged::RELEASE,
+ getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey2));
+
+ // Partial query fails.
+ HashableDimensionKey queryKey3;
+ getPartialWakelockKey(1001 /* uid */, &queryKey3);
+ EXPECT_EQ(WakelockStateChanged::RELEASE,
+ getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey3));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states with multiple primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::unique_ptr<LogEvent> event = CreateOverlayStateChangedEvent(
+ timestampNs, 1000 /* uid */, "package1", true /*using_alert_window*/,
+ OverlayStateChanged::ENTERED);
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey;
+ getOverlayKey(1000 /* uid */, "package1", &queryKey);
+ EXPECT_EQ(OverlayStateChanged::ENTERED,
+ getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged
+ * when there is an error extracting state from log event. Listener is not
+ * updated of state change.
+ */
+TEST(StateTrackerTest, TestStateChangeEventError) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event1 =
+ buildIncorrectOverlayEvent(1000 /* uid */, "package1", 1 /* state */);
+ std::shared_ptr<LogEvent> event2 = buildOverlayEventBadStateType(1001 /* uid */, "package2");
+
+ // check listener was updated
+ mgr.onLogEvent(*event1);
+ EXPECT_EQ(0, listener1->updates.size());
+ mgr.onLogEvent(*event2);
+ EXPECT_EQ(0, listener1->updates.size());
+}
+
+TEST(StateTrackerTest, TestStateQuery) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ sp<TestStateListener> listener3 = new TestStateListener();
+ sp<TestStateListener> listener4 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
+ mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener2);
+ mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener3);
+ mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener4);
+
+ std::unique_ptr<LogEvent> event1 = CreateUidProcessStateChangedEvent(
+ timestampNs, 1000 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::unique_ptr<LogEvent> event2 = CreateUidProcessStateChangedEvent(
+ timestampNs + 1000, 1001 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE); // state value:
+ // 1003
+ std::unique_ptr<LogEvent> event3 = CreateUidProcessStateChangedEvent(
+ timestampNs + 2000, 1002 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT); // state value: 1000
+ std::unique_ptr<LogEvent> event4 = CreateUidProcessStateChangedEvent(
+ timestampNs + 3000, 1001 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::unique_ptr<LogEvent> event5 = CreateScreenStateChangedEvent(
+ timestampNs + 4000, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ std::unique_ptr<LogEvent> event6 = CreateOverlayStateChangedEvent(
+ timestampNs + 5000, 1000 /*uid*/, "package1", true /*using_alert_window*/,
+ OverlayStateChanged::ENTERED);
+ std::unique_ptr<LogEvent> event7 = CreateOverlayStateChangedEvent(
+ timestampNs + 6000, 1000 /*uid*/, "package2", true /*using_alert_window*/,
+ OverlayStateChanged::EXITED);
+
+ std::vector<int> attributionUids = {1005};
+ std::vector<string> attributionTags = {"tag"};
+
+ std::unique_ptr<LogEvent> event8 = CreateAcquireWakelockEvent(
+ timestampNs + 7000, attributionUids, attributionTags, "wakelock1");
+ std::unique_ptr<LogEvent> event9 = CreateReleaseWakelockEvent(
+ timestampNs + 8000, attributionUids, attributionTags, "wakelock2");
+
+ mgr.onLogEvent(*event1);
+ mgr.onLogEvent(*event2);
+ mgr.onLogEvent(*event3);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event6);
+ mgr.onLogEvent(*event7);
+ mgr.onLogEvent(*event8);
+ mgr.onLogEvent(*event9);
+
+ // Query for UidProcessState of uid 1001
+ HashableDimensionKey queryKey1;
+ getUidProcessKey(1001, &queryKey1);
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+ getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for UidProcessState of uid 1004 - not in state map
+ HashableDimensionKey queryKey2;
+ getUidProcessKey(1004, &queryKey2);
+ EXPECT_EQ(-1, getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED,
+ queryKey2)); // default state
+
+ // Query for UidProcessState of uid 1001 - after change in state
+ mgr.onLogEvent(*event4);
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for ScreenState
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ getStateInt(mgr, util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+
+ // Query for OverlayState of uid 1000, package name "package2"
+ HashableDimensionKey queryKey3;
+ getOverlayKey(1000, "package2", &queryKey3);
+ EXPECT_EQ(OverlayStateChanged::EXITED,
+ getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey3));
+
+ // Query for WakelockState of uid 1005, tag 2
+ HashableDimensionKey queryKey4;
+ getPartialWakelockKey(1005, "wakelock2", &queryKey4);
+ EXPECT_EQ(WakelockStateChanged::RELEASE,
+ getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey4));
+
+ // Query for WakelockState of uid 1005, tag 1
+ HashableDimensionKey queryKey5;
+ getPartialWakelockKey(1005, "wakelock1", &queryKey5);
+ EXPECT_EQ(WakelockStateChanged::ACQUIRE,
+ getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey5));
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 050dbf8db7ad..c7838fcddb53 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -600,32 +600,51 @@ std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampN
return logEvent;
}
-//std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
-// const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
-// event->write(attributions);
-// event->write(jobName);
-// event->write(state);
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
-// const std::vector<AttributionNodeInternal>& attributions,
-// const string& name, uint64_t timestampNs) {
-// return CreateScheduledJobStateChangedEvent(
-// attributions, name, ScheduledJobStateChanged::STARTED, timestampNs);
-//}
-//
-//// Create log event when scheduled job finishes.
-//std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
-// const std::vector<AttributionNodeInternal>& attributions,
-// const string& name, uint64_t timestampNs) {
-// return CreateScheduledJobStateChangedEvent(
-// attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
-//}
-//
+std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
+ const vector<int>& attributionUids, const vector<string>& attributionTags,
+ const string& jobName, const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, jobName.c_str());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName) {
+ return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+ ScheduledJobStateChanged::STARTED, timestampNs);
+}
+
+// Create log event when scheduled job finishes.
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName) {
+ return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+ ScheduledJobStateChanged::FINISHED, timestampNs);
+}
+
std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
const vector<int>& attributionUids,
const vector<string>& attributionTags,
@@ -833,6 +852,62 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
return logEvent;
}
+std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const BleScanStateChanged::State state,
+ const bool filtered, const bool firstMatch,
+ const bool opportunistic) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::BLE_SCAN_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_writeInt32(statsEvent, filtered); // filtered
+ AStatsEvent_writeInt32(statsEvent, firstMatch); // first match
+ AStatsEvent_writeInt32(statsEvent, opportunistic); // opportunistic
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, const int32_t uid,
+ const string& packageName,
+ const bool usingAlertWindow,
+ const OverlayStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, packageName.c_str());
+ AStatsEvent_writeInt32(statsEvent, usingAlertWindow);
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key,
const shared_ptr<IPullAtomCallback>& puller,
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index ead041c29f28..05e1572e3aa9 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -195,14 +195,16 @@ std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level);
// Create log event when scheduled job starts.
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName);
// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName);
// Create log event when battery saver starts.
std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs);
@@ -247,6 +249,18 @@ std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, in
std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state);
+std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const BleScanStateChanged::State state,
+ const bool filtered, const bool firstMatch,
+ const bool opportunistic);
+
+std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, const int32_t uid,
+ const string& packageName,
+ const bool usingAlertWindow,
+ const OverlayStateChanged::State state);
+
// Helper function to create an AttributionNodeInternal proto.
AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 948546b18473..f590eb914aac 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -123,10 +123,14 @@ interface INotificationManager
// INotificationListener method.
@UnsupportedAppUsage
StatusBarNotification[] getActiveNotifications(String callingPkg);
+ StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg,
+ String callingAttributionTag);
@UnsupportedAppUsage
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count, boolean includeSnoozed);
+ StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg,
+ String callingAttributionTag, int count, boolean includeSnoozed);
- NotificationHistory getNotificationHistory(String callingPkg);
+ NotificationHistory getNotificationHistory(String callingPkg, String callingAttributionTag);
void registerListener(in INotificationListener listener, in ComponentName component, int userid);
void unregisterListener(in INotificationListener listener, int userid);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 811b9c082be2..0e97e3fe06ce 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -29,6 +29,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
@@ -841,7 +842,8 @@ public class NotificationManager {
}
/**
- * Returns the notification channel settings for a given channel and conversation id.
+ * Returns the notification channel settings for a given channel and
+ * {@link ShortcutInfo#getId() conversation id}.
*
* <p>The channel must belong to your package, or to a package you are an approved notification
* delegate for (see {@link #canNotifyAsPackage(String)}), or it will not be returned. To query
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 34a40aef147f..eb6901f6650e 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1214,7 +1214,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>If the camera device supports zoom-out from 1x zoom, minZoom will be less than 1.0, and
* setting {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to values less than 1.0 increases the camera's field
* of view.</p>
- * <p><b>Units</b>: A pair of zoom ratio in floating points: (minZoom, maxZoom)</p>
+ * <p><b>Units</b>: A pair of zoom ratio in floating-points: (minZoom, maxZoom)</p>
* <p><b>Range of valid values:</b><br></p>
* <p>maxZoom &gt;= 1.0 &gt;= minZoom</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0ee748287fa2..6905f83104cd 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2180,27 +2180,66 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
* crop to achieve aspect ratios different than the native camera sensor.</p>
* <p>By using this control, the application gains a simpler way to control zoom, which can
- * be a combination of optical and digital zoom. More specifically, for a logical
- * multi-camera with more than one focal length, using a floating point zoom ratio offers
- * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
- * less than 1.0 to zoom out to a wide field of view.</p>
- * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
- * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
- * activeArrayWidth, activeArrayHeight).</p>
- * <p>For example, if {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is 4032*3024, and the preview stream
- * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
- * one of two ways:</p>
+ * be a combination of optical and digital zoom. For example, a multi-camera system may
+ * contain more than one lens with different focal lengths, and the user can use optical
+ * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:
+ * <em> Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
+ * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.
+ * </em> Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</p>
+ * <p>To illustrate, here are several scenarios of different zoom ratios, crop regions,
+ * and output streams, for a hypothetical camera device with an active array of size
+ * <code>(2000,1500)</code>.</p>
* <ul>
- * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
- * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+ * <li>Camera Configuration:<ul>
+ * <li>Active array size: <code>2000x1500</code> (3 MP, 4:3 aspect ratio)</li>
+ * <li>Output stream #1: <code>640x480</code> (VGA, 4:3 aspect ratio)</li>
+ * <li>Output stream #2: <code>1280x720</code> (720p, 16:9 aspect ratio)</li>
+ * </ul>
+ * </li>
+ * <li>Case #1: 4:3 crop region with 2.0x zoom ratio<ul>
+ * <li>Zoomed field of view: 1/4 of original field of view</li>
+ * <li>Crop region: <code>Rect(0, 0, 2000, 1500) // (left, top, right, bottom)</code> (post zoom)</li>
+ * </ul>
+ * </li>
+ * <li><img alt="4:3 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png" /><ul>
+ * <li><code>640x480</code> stream source area: <code>(0, 0, 2000, 1500)</code> (equal to crop region)</li>
+ * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
+ * <li>Case #2: 16:9 crop region with 2.0x zoom.<ul>
+ * <li>Zoomed field of view: 1/4 of original field of view</li>
+ * <li>Crop region: <code>Rect(0, 187, 2000, 1312)</code></li>
+ * <li><img alt="16:9 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (pillarboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (equal to crop region)</li>
+ * </ul>
+ * </li>
+ * <li>Case #3: 1:1 crop region with 0.5x zoom out to ultrawide lens.<ul>
+ * <li>Zoomed field of view: 4x of original field of view (switched from wide lens to ultrawide lens)</li>
+ * <li>Crop region: <code>Rect(250, 0, 1750, 1500)</code></li>
+ * <li><img alt="1:1 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (letterboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(250, 328, 1750, 1172)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
* </ul>
- * <p>If the application intends to set aeRegions to be top-left quarter of the preview
- * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 2016, 1512) with
+ * <p>As seen from the graphs above, the coordinate system of cropRegion now changes to the
+ * effective after-zoom field-of-view, and is represented by the rectangle of (0, 0,
+ * activeArrayWith, activeArrayHeight). The same applies to AE/AWB/AF regions, and faces.
+ * This coordinate system change isn't applicable to RAW capture and its related
+ * metadata such as intrinsicCalibration and lensShadingMap.</p>
+ * <p>Using the same hypothetical example above, and assuming output stream #1 (640x480) is
+ * the viewfinder stream, the application can achieve 2.0x zoom in one of two ways:</p>
+ * <ul>
+ * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 2000, 1500)</li>
+ * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (500, 375, 1500, 1125)</li>
+ * </ul>
+ * <p>If the application intends to set aeRegions to be top-left quarter of the viewfinder
+ * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 1000, 750) with
* zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
- * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+ * region of (500, 375, 1000, 750) for zoomRatio of 1.0. If the application doesn't
* explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
- * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
- * such as intrinsicCalibration and lensShadingMap.</p>
* <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
* must only be used for letterboxing or pillarboxing of the sensor active array, and no
* FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
@@ -2216,7 +2255,6 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* @see CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CaptureRequest#SCALER_CROP_REGION
- * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@PublicKey
@NonNull
@@ -2574,12 +2612,15 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* frames before the lens can change to the requested focal length.
* While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
* be set to MOVING.</p>
- * <p>Optical zoom will not be supported on most devices.</p>
+ * <p>Optical zoom via this control will not be supported on most devices. Starting from API
+ * level 30, the camera device may combine optical and digital zoom through the
+ * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} control.</p>
* <p><b>Units</b>: Millimeters</p>
* <p><b>Range of valid values:</b><br>
* {@link CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS android.lens.info.availableFocalLengths}</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#LENS_APERTURE
* @see CaptureRequest#LENS_FOCUS_DISTANCE
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 096aa0cd27b3..be03502eb943 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2410,27 +2410,66 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
* crop to achieve aspect ratios different than the native camera sensor.</p>
* <p>By using this control, the application gains a simpler way to control zoom, which can
- * be a combination of optical and digital zoom. More specifically, for a logical
- * multi-camera with more than one focal length, using a floating point zoom ratio offers
- * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
- * less than 1.0 to zoom out to a wide field of view.</p>
- * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
- * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
- * activeArrayWidth, activeArrayHeight).</p>
- * <p>For example, if {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is 4032*3024, and the preview stream
- * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
- * one of two ways:</p>
+ * be a combination of optical and digital zoom. For example, a multi-camera system may
+ * contain more than one lens with different focal lengths, and the user can use optical
+ * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:
+ * <em> Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
+ * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.
+ * </em> Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</p>
+ * <p>To illustrate, here are several scenarios of different zoom ratios, crop regions,
+ * and output streams, for a hypothetical camera device with an active array of size
+ * <code>(2000,1500)</code>.</p>
* <ul>
- * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
- * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+ * <li>Camera Configuration:<ul>
+ * <li>Active array size: <code>2000x1500</code> (3 MP, 4:3 aspect ratio)</li>
+ * <li>Output stream #1: <code>640x480</code> (VGA, 4:3 aspect ratio)</li>
+ * <li>Output stream #2: <code>1280x720</code> (720p, 16:9 aspect ratio)</li>
+ * </ul>
+ * </li>
+ * <li>Case #1: 4:3 crop region with 2.0x zoom ratio<ul>
+ * <li>Zoomed field of view: 1/4 of original field of view</li>
+ * <li>Crop region: <code>Rect(0, 0, 2000, 1500) // (left, top, right, bottom)</code> (post zoom)</li>
+ * </ul>
+ * </li>
+ * <li><img alt="4:3 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png" /><ul>
+ * <li><code>640x480</code> stream source area: <code>(0, 0, 2000, 1500)</code> (equal to crop region)</li>
+ * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
+ * <li>Case #2: 16:9 crop region with 2.0x zoom.<ul>
+ * <li>Zoomed field of view: 1/4 of original field of view</li>
+ * <li>Crop region: <code>Rect(0, 187, 2000, 1312)</code></li>
+ * <li><img alt="16:9 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (pillarboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (equal to crop region)</li>
+ * </ul>
+ * </li>
+ * <li>Case #3: 1:1 crop region with 0.5x zoom out to ultrawide lens.<ul>
+ * <li>Zoomed field of view: 4x of original field of view (switched from wide lens to ultrawide lens)</li>
+ * <li>Crop region: <code>Rect(250, 0, 1750, 1500)</code></li>
+ * <li><img alt="1:1 aspect ratio crop diagram" src="/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (letterboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(250, 328, 1750, 1172)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
* </ul>
- * <p>If the application intends to set aeRegions to be top-left quarter of the preview
- * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 2016, 1512) with
+ * <p>As seen from the graphs above, the coordinate system of cropRegion now changes to the
+ * effective after-zoom field-of-view, and is represented by the rectangle of (0, 0,
+ * activeArrayWith, activeArrayHeight). The same applies to AE/AWB/AF regions, and faces.
+ * This coordinate system change isn't applicable to RAW capture and its related
+ * metadata such as intrinsicCalibration and lensShadingMap.</p>
+ * <p>Using the same hypothetical example above, and assuming output stream #1 (640x480) is
+ * the viewfinder stream, the application can achieve 2.0x zoom in one of two ways:</p>
+ * <ul>
+ * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 2000, 1500)</li>
+ * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (500, 375, 1500, 1125)</li>
+ * </ul>
+ * <p>If the application intends to set aeRegions to be top-left quarter of the viewfinder
+ * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 1000, 750) with
* zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
- * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+ * region of (500, 375, 1000, 750) for zoomRatio of 1.0. If the application doesn't
* explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
- * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
- * such as intrinsicCalibration and lensShadingMap.</p>
* <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
* must only be used for letterboxing or pillarboxing of the sensor active array, and no
* FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
@@ -2446,7 +2485,6 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* @see CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CaptureRequest#SCALER_CROP_REGION
- * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@PublicKey
@NonNull
@@ -2848,12 +2886,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* frames before the lens can change to the requested focal length.
* While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
* be set to MOVING.</p>
- * <p>Optical zoom will not be supported on most devices.</p>
+ * <p>Optical zoom via this control will not be supported on most devices. Starting from API
+ * level 30, the camera device may combine optical and digital zoom through the
+ * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} control.</p>
* <p><b>Units</b>: Millimeters</p>
* <p><b>Range of valid values:</b><br>
* {@link CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS android.lens.info.availableFocalLengths}</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#LENS_APERTURE
* @see CaptureRequest#LENS_FOCUS_DISTANCE
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 785b51d2dee9..cdc00195c169 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2224,15 +2224,27 @@ public final class PowerManager {
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
* This broadcast is only sent to registered receivers.
*
+ * @deprecated This is sent at the same time as {@link #ACTION_POWER_SAVE_MODE_CHANGED} so it
+ * does not provide advanced warning. As such it will be removed in future Android versions.
+ * Use {@link #ACTION_POWER_SAVE_MODE_CHANGED} and {@link #isPowerSaveMode()} instead.
+ *
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ publicAlternatives = "Use {@link #ACTION_POWER_SAVE_MODE_CHANGED} instead.")
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_POWER_SAVE_MODE_CHANGING
= "android.os.action.POWER_SAVE_MODE_CHANGING";
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * @deprecated Use {@link #isPowerSaveMode()} instead.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ publicAlternatives = "Use {@link #isPowerSaveMode()} instead.")
+ @Deprecated
public static final String EXTRA_POWER_SAVE_MODE = "mode";
/**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 43f80f1490ad..e6bd84391fef 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.InsetsState.ITYPE_IME;
+import static android.view.InsetsState.toInternalType;
import static android.view.InsetsState.toPublicType;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
@@ -26,8 +27,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONT
import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -38,11 +37,9 @@ import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.RemoteException;
-import android.renderscript.Sampler.Value;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.util.Property;
import android.util.SparseArray;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
@@ -467,7 +464,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (!localStateChanged && mLastDispachedState.equals(state)) {
return false;
}
- mState.set(state);
+ updateState(state);
mLastDispachedState.set(state, true /* copySources */);
applyLocalVisibilityOverride();
if (localStateChanged) {
@@ -479,6 +476,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return true;
}
+ private void updateState(InsetsState newState) {
+ mState.setDisplayFrame(newState.getDisplayFrame());
+ for (int i = newState.getSourcesCount() - 1; i >= 0; i--) {
+ InsetsSource source = newState.sourceAt(i);
+ getSourceConsumer(source.getType()).updateSource(source);
+ }
+ for (int i = mState.getSourcesCount() - 1; i >= 0; i--) {
+ InsetsSource source = mState.sourceAt(i);
+ if (newState.peekSource(source.getType()) == null) {
+ mState.removeSource(source.getType());
+ }
+ }
+ }
+
/**
* @see InsetsState#calculateInsets
*/
@@ -858,8 +869,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
control.cancel();
}
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
- if (mRunningAnimations.get(i).runner == control) {
+ RunningAnimation runningAnimation = mRunningAnimations.get(i);
+ if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
+ ArraySet<Integer> types = toInternalType(control.getTypes());
+ for (int j = types.size() - 1; j >= 0; j--) {
+ if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
+ mViewRoot.notifyInsetsChanged();
+ }
+ }
break;
}
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 332573449e18..f36621c0a49e 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -16,11 +16,13 @@
package android.view;
+import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsState.toPublicType;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.graphics.Rect;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetsType;
@@ -64,6 +66,8 @@ public class InsetsSourceConsumer {
private final Supplier<Transaction> mTransactionSupplier;
private @Nullable InsetsSourceControl mSourceControl;
private boolean mHasWindowFocus;
+ private Rect mPendingFrame;
+ private Rect mPendingVisibleFrame;
public InsetsSourceConsumer(@InternalInsetsType int type, InsetsState state,
Supplier<Transaction> transactionSupplier, InsetsController controller) {
@@ -215,6 +219,38 @@ public class InsetsSourceConsumer {
// no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
}
+ void updateSource(InsetsSource newSource) {
+ InsetsSource source = mState.peekSource(mType);
+ if (source == null || mController.getAnimationType(mType) == ANIMATION_TYPE_NONE
+ || source.getFrame().equals(newSource.getFrame())) {
+ mState.addSource(newSource);
+ return;
+ }
+
+ // Frame is changing while animating. Keep note of the new frame but keep existing frame
+ // until animaition is finished.
+ newSource = new InsetsSource(newSource);
+ mPendingFrame = new Rect(newSource.getFrame());
+ mPendingVisibleFrame = newSource.getVisibleFrame() != null
+ ? new Rect(newSource.getVisibleFrame())
+ : null;
+ newSource.setFrame(source.getFrame());
+ newSource.setVisibleFrame(source.getVisibleFrame());
+ mState.addSource(newSource);
+ }
+
+ boolean notifyAnimationFinished() {
+ if (mPendingFrame != null) {
+ InsetsSource source = mState.getSource(mType);
+ source.setFrame(mPendingFrame);
+ source.setVisibleFrame(mPendingVisibleFrame);
+ mPendingFrame = null;
+ mPendingVisibleFrame = null;
+ return true;
+ }
+ return false;
+ }
+
/**
* Sets requested visibility from the client, regardless of whether we are able to control it at
* the moment.
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 7d97a91b7435..8943da4a2fc0 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -755,8 +755,9 @@ public class Toast {
/**
* Callback object to be called when the toast is shown or hidden.
*
- * Callback methods will be called on the looper thread provided on construction.
+ * <p>Callback methods will be called on the looper thread used for the {@link Toast} object.
*
+ * @see #makeText(Context, Looper, CharSequence, int)
* @see #addCallback(Callback)
*/
public abstract static class Callback {
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 34a1016f0ae9..efdb51dcdfa9 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -31,6 +31,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -638,6 +639,32 @@ public class InsetsControllerTest {
});
}
+ @Test
+ public void testFrameUpdateDuringAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+
+ mController.onControlsChanged(createSingletonControl(ITYPE_IME));
+
+ // Pretend IME is calling
+ mController.show(ime(), true /* fromIme */);
+
+ InsetsState copy = new InsetsState(mController.getState(), true /* copySources */);
+ copy.getSource(ITYPE_IME).setFrame(0, 1, 2, 3);
+ copy.getSource(ITYPE_IME).setVisibleFrame(new Rect(4, 5, 6, 7));
+ mController.onStateChanged(copy);
+ assertNotEquals(new Rect(0, 1, 2, 3),
+ mController.getState().getSource(ITYPE_IME).getFrame());
+ assertNotEquals(new Rect(4, 5, 6, 7),
+ mController.getState().getSource(ITYPE_IME).getVisibleFrame());
+ mController.cancelExistingAnimation();
+ assertEquals(new Rect(0, 1, 2, 3),
+ mController.getState().getSource(ITYPE_IME).getFrame());
+ assertEquals(new Rect(4, 5, 6, 7),
+ mController.getState().getSource(ITYPE_IME).getVisibleFrame());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
diff --git a/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png
new file mode 100644
index 000000000000..1acc59d167fc
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png
new file mode 100644
index 000000000000..4ab9ca4fa580
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png
new file mode 100644
index 000000000000..d74e673a9ce1
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png
Binary files differ
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 42bf03e6de05..f4a358de1c41 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -90,6 +90,7 @@ class ProtoOutputStream
{
public:
ProtoOutputStream();
+ ProtoOutputStream(sp<EncodedBuffer> buffer);
~ProtoOutputStream();
/**
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
index 7ffd8874a8fb..96b54c63a836 100644
--- a/libs/protoutil/src/EncodedBuffer.cpp
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "libprotoutil"
#include <stdlib.h>
+#include <sys/mman.h>
#include <android/util/EncodedBuffer.h>
#include <android/util/protobuf.h>
@@ -82,14 +83,16 @@ EncodedBuffer::Pointer::copy() const
}
// ===========================================================
-EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
+EncodedBuffer::EncodedBuffer() : EncodedBuffer(BUFFER_SIZE)
{
}
EncodedBuffer::EncodedBuffer(size_t chunkSize)
:mBuffers()
{
- mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+ // Align chunkSize to memory page size
+ chunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+ mChunkSize = (chunkSize / PAGE_SIZE + ((chunkSize % PAGE_SIZE == 0) ? 0 : 1)) * PAGE_SIZE;
mWp = Pointer(mChunkSize);
mEp = Pointer(mChunkSize);
}
@@ -98,7 +101,7 @@ EncodedBuffer::~EncodedBuffer()
{
for (size_t i=0; i<mBuffers.size(); i++) {
uint8_t* buf = mBuffers[i];
- free(buf);
+ munmap(buf, mChunkSize);
}
}
@@ -135,7 +138,10 @@ EncodedBuffer::writeBuffer()
if (mWp.index() > mBuffers.size()) return NULL;
uint8_t* buf = NULL;
if (mWp.index() == mBuffers.size()) {
- buf = (uint8_t*)malloc(mChunkSize);
+ // Use mmap instead of malloc to ensure memory alignment i.e. no fragmentation so that
+ // the mem region can be immediately reused by the allocator after calling munmap()
+ buf = (uint8_t*)mmap(NULL, mChunkSize, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (buf == NULL) return NULL; // This indicates NO_MEMORY
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index ea9b79a0353f..fcf82eed4eb1 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -26,8 +26,12 @@
namespace android {
namespace util {
-ProtoOutputStream::ProtoOutputStream()
- :mBuffer(new EncodedBuffer()),
+ProtoOutputStream::ProtoOutputStream(): ProtoOutputStream(new EncodedBuffer())
+{
+}
+
+ProtoOutputStream::ProtoOutputStream(sp<EncodedBuffer> buffer)
+ :mBuffer(buffer),
mCopyBegin(0),
mCompact(false),
mDepth(0),
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 383202b20550..fffdd683f22c 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4579,6 +4579,7 @@ public class AudioManager {
* {@hide}
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
final IAudioService service = getService();
try {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index da93db7b37f6..f2d40cef83c7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -300,11 +300,6 @@
android:exported="false"
android:permission="com.android.systemui.permission.SELF" />
- <service android:name=".assist.AssistHandleService"
- android:exported="true"
- android:enabled="false"
- />
-
<!-- started from PhoneWindowManager
TODO: Should have an android:permission attribute -->
<service android:name=".screenshot.TakeScreenshotService"
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
index a06f434d068c..65b04fd8fd99 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_activity.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
@@ -19,6 +19,7 @@
android:id="@+id/bubble_overflow_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingTop="@dimen/bubble_overflow_padding"
android:orientation="vertical"
android:layout_gravity="center_horizontal">
diff --git a/packages/SystemUI/res/layout/bubble_overflow_view.xml b/packages/SystemUI/res/layout/bubble_overflow_view.xml
new file mode 100644
index 000000000000..d67c81d67ada
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_overflow_view.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bubble_overflow_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.android.systemui.bubbles.BadgedImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bubble_view"
+ android:layout_gravity="center"
+ android:layout_width="@dimen/individual_bubble_size"
+ android:layout_height="@dimen/individual_bubble_size"/>
+
+ <TextView
+ android:id="@+id/bubble_view_name"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
+ android:textColor="?android:attr/textColorSecondary"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:layout_gravity="center"
+ android:gravity="center"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
index 74fc167c4632..41282301ab1c 100644
--- a/packages/SystemUI/res/layout/controls_no_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -50,7 +50,6 @@
<TextView
style="@style/TextAppearance.ControlSetup.Subtitle"
android:id="@+id/controls_subtitle"
- android:visibility="gone"
android:layout_marginTop="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/keyguard_media_header.xml b/packages/SystemUI/res/layout/keyguard_media_header.xml
index 9c2d244cb8ec..de9ef218083b 100644
--- a/packages/SystemUI/res/layout/keyguard_media_header.xml
+++ b/packages/SystemUI/res/layout/keyguard_media_header.xml
@@ -52,7 +52,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:gravity="center_horizontal|fill_vertical"
+ android:gravity="center"
android:padding="16dp"
>
<ImageView
@@ -67,7 +67,7 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
- android:layout_height="@dimen/qs_media_album_size"
+ android:layout_height="wrap_content"
android:layout_weight="1"
>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
index 9ef8c1dbbb95..fe8557bfcce4 100644
--- a/packages/SystemUI/res/layout/qs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -56,7 +56,7 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
- android:layout_height="@dimen/qs_media_album_size"
+ android:layout_height="wrap_content"
android:layout_weight="1"
>
<LinearLayout
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e45cbecd3aa1..432cd749abbd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1150,8 +1150,8 @@
<dimen name="bubble_overflow_height">380dp</dimen>
<!-- Bubble overflow padding when there are no bubbles -->
<dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
- <!-- Margin of overflow bubbles -->
- <dimen name="bubble_overflow_margin">16dp</dimen>
+ <!-- Padding of container for overflow bubbles -->
+ <dimen name="bubble_overflow_padding">5dp</dimen>
<!-- Height of the triangle that points to the expanded bubble -->
<dimen name="bubble_pointer_height">4dp</dimen>
<!-- Width of the triangle that points to the expanded bubble -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f7ad13425ef6..c8c35c704297 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2636,14 +2636,17 @@
<!-- Quick Controls strings -->
<!-- Quick Controls empty state, title [CHAR LIMIT=30] -->
- <string name="quick_controls_title">Quick Controls</string>
+ <string name="quick_controls_title">Quick controls</string>
<!-- Quick Controls empty state, subtitle [CHAR LIMIT=100] -->
<string name="quick_controls_subtitle">Add controls for your connected devices</string>
- <!-- Controls management providers screen title [CHAR LIMIT=30]-->
- <string name="controls_providers_title">Add Controls</string>
- <!-- Controls management providers screen subtitle [CHAR LIMIT=NONE] -->
- <string name="controls_providers_subtitle">Choose app to add controls</string>
+ <!-- Quick Controls setup, title [CHAR LIMIT=50] -->
+ <string name="quick_controls_setup_title">Set up quick controls</string>
+ <!-- Quick Controls setup, subtitle [CHAR LIMIT=100] -->
+ <string name="quick_controls_setup_subtitle">Hold the Power button to access your controls</string>
+
+ <!-- Controls management providers screen title [CHAR LIMIT=60]-->
+ <string name="controls_providers_title">Choose app to add controls</string>
<!-- Number of favorites for controls management screen [CHAR LIMIT=NONE]-->
<plurals name="controls_number_of_favorites">
<item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> control added.</item>
@@ -2679,12 +2682,8 @@
<string name="controls_pin_verifying">Verifying\u2026</string>
<!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
<string name="controls_pin_instructions">Enter PIN</string>
- <!-- Controls passphrase entry dialog, text hint [CHAR LIMIT=30] -->
- <string name="controls_passphrase_instructions">Enter passphrase</string>
<!-- Controls PIN entry dialog, text hint, retry [CHAR LIMIT=30] -->
<string name="controls_pin_instructions_retry">Try another PIN</string>
- <!-- Controls passphrase entry dialog, text hint, retry [CHAR LIMIT=50] -->
- <string name="controls_passphrase_instructions_retry">Try another passphrase</string>
<!-- Controls confirmation dialog, waiting to confirm [CHAR LIMIT=30] -->
<string name="controls_confirmation_confirming">Confirming\u2026</string>
<!-- Controls confirmation dialog, user prompt [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
index b0017269ff7e..4fcacc276ac1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
@@ -114,7 +114,9 @@ public class KeyguardMediaPlayer {
throw new IllegalStateException("cannot update controls, views not bound");
}
if (mediaMetadata == null) {
- throw new IllegalArgumentException("media metadata was null");
+ mMediaNotifView.setVisibility(View.GONE);
+ Log.d(TAG, "media metadata was null");
+ return;
}
mMediaNotifView.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 18357a95714b..3afe19f926ec 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -966,17 +966,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
boolean changed = false;
if (enabled && (oldIntent == null)) {
- Intent intent = new Intent(
- DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE);
- ComponentName profileOwnerComponent =
- mDevicePolicyManager.getProfileOwnerAsUser(userId);
- intent.setComponent(profileOwnerComponent);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, 0);
- if (resolveInfo != null) {
- Intent newIntent = new Intent();
- newIntent.setComponent(profileOwnerComponent);
- mSecondaryLockscreenRequirement.put(userId, newIntent);
- changed = true;
+ ComponentName poComponent = mDevicePolicyManager.getProfileOwnerAsUser(userId);
+ if (poComponent == null) {
+ Log.e(TAG, "No profile owner found for User " + userId);
+ } else {
+ Intent intent =
+ new Intent(DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE)
+ .setPackage(poComponent.getPackageName());
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, 0);
+ if (resolveInfo != null && resolveInfo.serviceInfo != null) {
+ Intent launchIntent =
+ new Intent().setComponent(resolveInfo.serviceInfo.getComponentName());
+ mSecondaryLockscreenRequirement.put(userId, launchIntent);
+ changed = true;
+ }
}
} else if (!enabled && (oldIntent != null)) {
mSecondaryLockscreenRequirement.put(userId, null);
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index e2b12daf441e..59af458e2402 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -86,7 +86,8 @@ public class ExpandHelper implements Gefingerpoken {
private float mInitialTouchSpan;
private float mLastFocusY;
private float mLastSpanY;
- private int mTouchSlop;
+ private final int mTouchSlop;
+ private final float mSlopMultiplier;
private float mLastMotionY;
private float mPullGestureMinXSpan;
private Callback mCallback;
@@ -177,6 +178,7 @@ public class ExpandHelper implements Gefingerpoken {
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
+ mSlopMultiplier = configuration.getAmbiguousGestureMultiplier();
mSGD = new ScaleGestureDetector(context, mScaleGestureListener);
mFlingAnimationUtils = new FlingAnimationUtils(mContext.getResources().getDisplayMetrics(),
@@ -258,6 +260,13 @@ public class ExpandHelper implements Gefingerpoken {
mScrollAdapter = adapter;
}
+ private float getTouchSlop(MotionEvent event) {
+ // Adjust the touch slop if another gesture may be being performed.
+ return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mTouchSlop * mSlopMultiplier
+ : mTouchSlop;
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!isEnabled()) {
@@ -303,7 +312,7 @@ public class ExpandHelper implements Gefingerpoken {
if (mWatchingForPull) {
final float yDiff = ev.getRawY() - mInitialTouchY;
final float xDiff = ev.getRawX() - mInitialTouchX;
- if (yDiff > mTouchSlop && yDiff > Math.abs(xDiff)) {
+ if (yDiff > getTouchSlop(ev) && yDiff > Math.abs(xDiff)) {
if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
mWatchingForPull = false;
if (mResizedView != null && !isFullyExpanded(mResizedView)) {
@@ -431,7 +440,7 @@ public class ExpandHelper implements Gefingerpoken {
if (mWatchingForPull) {
final float yDiff = ev.getRawY() - mInitialTouchY;
final float xDiff = ev.getRawX() - mInitialTouchX;
- if (yDiff > mTouchSlop && yDiff > Math.abs(xDiff)) {
+ if (yDiff > getTouchSlop(ev) && yDiff > Math.abs(xDiff)) {
if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
mWatchingForPull = false;
if (mResizedView != null && !isFullyExpanded(mResizedView)) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 02a452182d36..d17ca4041b31 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -69,6 +69,7 @@ public class SwipeHelper implements Gefingerpoken {
private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
+ private final float mSlopMultiplier;
private final Callback mCallback;
private final int mSwipeDirection;
private final VelocityTracker mVelocityTracker;
@@ -84,11 +85,28 @@ public class SwipeHelper implements Gefingerpoken {
private float mTranslation = 0;
private boolean mMenuRowIntercepting;
- private boolean mLongPressSent;
- private Runnable mWatchLongPress;
private final long mLongPressTimeout;
+ private boolean mLongPressSent;
+ private final float[] mDownLocation = new float[2];
+ private final Runnable mPerformLongPress = new Runnable() {
+
+ private final int[] mViewOffset = new int[2];
+
+ @Override
+ public void run() {
+ if (mCurrView != null && !mLongPressSent) {
+ mLongPressSent = true;
+ if (mCurrView instanceof ExpandableNotificationRow) {
+ mCurrView.getLocationOnScreen(mViewOffset);
+ final int x = (int) mDownLocation[0] - mViewOffset[0];
+ final int y = (int) mDownLocation[1] - mViewOffset[1];
+ mCurrView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+ ((ExpandableNotificationRow) mCurrView).doLongClickCallback(x, y);
+ }
+ }
+ }
+ };
- final private int[] mTmpPos = new int[2];
private final int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
@@ -102,7 +120,9 @@ public class SwipeHelper implements Gefingerpoken {
mHandler = new Handler();
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
- mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
+ mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
@@ -255,10 +275,7 @@ public class SwipeHelper implements Gefingerpoken {
}
public void cancelLongPress() {
- if (mWatchLongPress != null) {
- mHandler.removeCallbacks(mWatchLongPress);
- mWatchLongPress = null;
- }
+ mHandler.removeCallbacks(mPerformLongPress);
}
@Override
@@ -287,27 +304,9 @@ public class SwipeHelper implements Gefingerpoken {
mInitialTouchPos = getPos(ev);
mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
mTranslation = getTranslation(mCurrView);
- if (mWatchLongPress == null) {
- mWatchLongPress = new Runnable() {
- @Override
- public void run() {
- if (mCurrView != null && !mLongPressSent) {
- mLongPressSent = true;
- mCurrView.getLocationOnScreen(mTmpPos);
- final int x = (int) ev.getRawX() - mTmpPos[0];
- final int y = (int) ev.getRawY() - mTmpPos[1];
- if (mCurrView instanceof ExpandableNotificationRow) {
- mCurrView.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
- ExpandableNotificationRow currRow =
- (ExpandableNotificationRow) mCurrView;
- currRow.doLongClickCallback(x, y);
- }
- }
- }
- };
- }
- mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
+ mDownLocation[0] = ev.getRawX();
+ mDownLocation[1] = ev.getRawY();
+ mHandler.postDelayed(mPerformLongPress, mLongPressTimeout);
}
break;
@@ -318,7 +317,12 @@ public class SwipeHelper implements Gefingerpoken {
float perpendicularPos = getPerpendicularPos(ev);
float delta = pos - mInitialTouchPos;
float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
- if (Math.abs(delta) > mPagingTouchSlop
+ // Adjust the touch slop if another gesture may be being performed.
+ final float pagingTouchSlop =
+ ev.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mPagingTouchSlop * mSlopMultiplier
+ : mPagingTouchSlop;
+ if (Math.abs(delta) > pagingTouchSlop
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
if (mCallback.canChildBeDragged(mCurrView)) {
mCallback.onBeginDrag(mCurrView);
@@ -327,6 +331,11 @@ public class SwipeHelper implements Gefingerpoken {
mTranslation = getTranslation(mCurrView);
}
cancelLongPress();
+ } else if (ev.getClassification() == MotionEvent.CLASSIFICATION_DEEP_PRESS
+ && mHandler.hasCallbacks(mPerformLongPress)) {
+ // Accelerate the long press signal.
+ cancelLongPress();
+ mPerformLongPress.run();
}
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
deleted file mode 100644
index 9ceafc674d34..000000000000
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.assist
-
-import android.app.Service
-import android.content.Intent
-import android.os.IBinder
-import dagger.Lazy
-import javax.inject.Inject
-
-class AssistHandleService @Inject constructor(private val assistManager: Lazy<AssistManager>)
- : Service() {
-
- private val binder = object : IAssistHandleService.Stub() {
- override fun requestAssistHandles() {
- assistManager.get().requestAssistHandles()
- }
- }
-
- override fun onBind(intent: Intent?): IBinder? {
- return binder
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
index 96939b010555..6f5a17dca432 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
@@ -16,7 +16,6 @@
package com.android.systemui.assist;
-import android.app.Service;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
@@ -34,11 +33,8 @@ import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
/** Module for dagger injections related to the Assistant. */
@Module
@@ -91,9 +87,4 @@ public abstract class AssistModule {
static Clock provideSystemClock() {
return SystemClock::uptimeMillis;
}
-
- @Binds
- @IntoMap
- @ClassKey(AssistHandleService.class)
- abstract Service bindAssistHandleService(AssistHandleService assistHandleService);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index 7636c6712e41..b65198595095 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -21,14 +21,20 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
+import android.app.Notification;
+import android.app.Person;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -67,13 +73,22 @@ public class BubbleOverflowActivity extends Activity {
mEmptyState = findViewById(R.id.bubble_overflow_empty_state);
mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
+
+ Resources res = getResources();
+ final int columns = res.getInteger(R.integer.bubbles_overflow_columns);
mRecyclerView.setLayoutManager(
- new GridLayoutManager(getApplicationContext(),
- getResources().getInteger(R.integer.bubbles_overflow_columns)));
+ new GridLayoutManager(getApplicationContext(), columns));
+
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ final int viewWidth = displayMetrics.widthPixels / columns;
+
+ final int maxOverflowBubbles = res.getInteger(R.integer.bubbles_max_overflow);
+ final int rows = (int) Math.ceil((double) maxOverflowBubbles / columns);
+ final int viewHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height) / rows;
- int bubbleMargin = getResources().getDimensionPixelSize(R.dimen.bubble_overflow_margin);
mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
- mBubbleController::promoteBubbleFromOverflow, bubbleMargin);
+ mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight);
mRecyclerView.setAdapter(mAdapter);
onDataChanged(mBubbleController.getOverflowBubbles());
mBubbleController.setOverflowCallback(() -> {
@@ -139,39 +154,48 @@ public class BubbleOverflowActivity extends Activity {
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
- private int mBubbleMargin;
+ private int mWidth;
+ private int mHeight;
- public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble,
- int bubbleMargin) {
+ public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble, int width,
+ int height) {
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
- mBubbleMargin = bubbleMargin;
+ mWidth = width;
+ mHeight = height;
}
@Override
public BubbleOverflowAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
- BadgedImageView view = (BadgedImageView) LayoutInflater.from(parent.getContext())
- .inflate(R.layout.bubble_view, parent, false);
+ LinearLayout overflowView = (LinearLayout) LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.bubble_overflow_view, parent, false);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- );
- params.setMargins(mBubbleMargin, mBubbleMargin, mBubbleMargin, mBubbleMargin);
- view.setLayoutParams(params);
- return new ViewHolder(view);
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ params.width = mWidth;
+ params.height = mHeight;
+ overflowView.setLayoutParams(params);
+ return new ViewHolder(overflowView);
}
@Override
public void onBindViewHolder(ViewHolder vh, int index) {
- Bubble bubble = mBubbles.get(index);
+ Bubble b = mBubbles.get(index);
- vh.mBadgedImageView.update(bubble);
- vh.mBadgedImageView.setOnClickListener(view -> {
- mBubbles.remove(bubble);
+ vh.iconView.update(b);
+ vh.iconView.setOnClickListener(view -> {
+ mBubbles.remove(b);
notifyDataSetChanged();
- mPromoteBubbleFromOverflow.accept(bubble);
+ mPromoteBubbleFromOverflow.accept(b);
});
+
+ Bubble.FlyoutMessage message = b.getFlyoutMessage();
+ if (message != null && message.senderName != null) {
+ vh.textView.setText(message.senderName);
+ } else {
+ vh.textView.setText(b.getAppName());
+ }
}
@Override
@@ -180,11 +204,13 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
}
public static class ViewHolder extends RecyclerView.ViewHolder {
- public BadgedImageView mBadgedImageView;
+ public BadgedImageView iconView;
+ public TextView textView;
- public ViewHolder(BadgedImageView v) {
+ public ViewHolder(LinearLayout v) {
super(v);
- mBadgedImageView = v;
+ iconView = v.findViewById(R.id.bubble_view);
+ textView = v.findViewById(R.id.bubble_view_name);
}
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 098caf61a873..0c41f7e5df5a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -84,8 +84,6 @@ class ControlsProviderSelectorActivity @Inject constructor(
requireViewById<TextView>(R.id.title).text =
resources.getText(R.string.controls_providers_title)
- requireViewById<TextView>(R.id.subtitle).text =
- resources.getText(R.string.controls_providers_subtitle)
requireViewById<Button>(R.id.done).setOnClickListener {
this@ControlsProviderSelectorActivity.finishAffinity()
@@ -117,4 +115,4 @@ class ControlsProviderSelectorActivity @Inject constructor(
currentUserTracker.stopTracking()
super.onDestroy()
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 34dcca2859e7..b0db4370f38d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -172,7 +172,7 @@ class ControlsUiControllerImpl @Inject constructor (
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
- subtitle.setVisibility(View.VISIBLE)
+ subtitle.setText(context.resources.getString(R.string.controls_seeding_in_progress))
}
private fun showInitialSetupView(items: List<SelectionItem>) {
@@ -184,6 +184,9 @@ class ControlsUiControllerImpl @Inject constructor (
val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
viewGroup.setOnClickListener(launchSelectorActivityListener(context))
+ val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
+ subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle))
+
val iconRowGroup = parent.requireViewById(R.id.controls_icon_row) as ViewGroup
items.forEach {
val imageView = inflater.inflate(R.layout.controls_icon, viewGroup, false) as ImageView
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 902b5785c30a..6ce5e7cf506c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -346,6 +346,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
+ .resetScale(tx, mLeash, destinationBounds)
.round(tx, mLeash, mInPip);
scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 014f3b51b4dc..1a01cfedb82e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -208,7 +208,8 @@ public class PipResizeGestureHandler {
final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
- mMinSize.y, mMaxSize, true, true));
+ mMinSize.y, mMaxSize, true,
+ mLastDownBounds.width() > mLastDownBounds.height()));
mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 5adee40613e6..4fa782269c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -48,7 +48,8 @@ public class DragDownHelper implements Gefingerpoken {
private float mInitialTouchX;
private float mInitialTouchY;
private boolean mDraggingDown;
- private float mTouchSlop;
+ private final float mTouchSlop;
+ private final float mSlopMultiplier;
private DragDownCallback mDragDownCallback;
private View mHost;
private final int[] mTemp2 = new int[2];
@@ -62,7 +63,9 @@ public class DragDownHelper implements Gefingerpoken {
FalsingManager falsingManager) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = configuration.getScaledTouchSlop();
+ mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mCallback = callback;
mDragDownCallback = dragDownCallback;
mHost = host;
@@ -85,7 +88,12 @@ public class DragDownHelper implements Gefingerpoken {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
- if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ // Adjust the touch slop if another gesture may be being performed.
+ final float touchSlop =
+ event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mTouchSlop * mSlopMultiplier
+ : mTouchSlop;
+ if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
mFalsingManager.onNotificatonStartDraggingDown();
mDraggingDown = true;
captureStartingChild(mInitialTouchX, mInitialTouchY);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 4d4a2ded08ca..be8af82f8baf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -222,6 +222,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private boolean mIsScrollerBoundSet;
private Runnable mFinishScrollingCallback;
private int mTouchSlop;
+ private float mSlopMultiplier;
private int mMinimumVelocity;
private int mMaximumVelocity;
private int mOverflingDistance;
@@ -1022,6 +1023,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
+ mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mOverflingDistance = configuration.getScaledOverflingDistance();
@@ -3744,15 +3746,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mLongPressListener = listener;
}
+ private float getTouchSlop(MotionEvent event) {
+ // Adjust the touch slop if another gesture may be being performed.
+ return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mTouchSlop * mSlopMultiplier
+ : mTouchSlop;
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onTouchEvent(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked() == MotionEvent.ACTION_UP;
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
boolean swipingInProgress = mSwipingInProgress;
- if (mIsExpanded && !swipingInProgress && !mOnlyScrollingInThisMotion) {
+ if (mIsExpanded && !swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
if (isCancelOrUp) {
mExpandHelper.onlyObserveMovements(false);
}
@@ -3778,7 +3788,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
// Check if we need to clear any snooze leavebehinds
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
&& guts.getGutsContent() instanceof NotificationSnooze) {
NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
@@ -3891,12 +3900,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
int deltaY = mLastMotionY - y;
final int xDiff = Math.abs(x - mDownX);
final int yDiff = Math.abs(deltaY);
- if (!mIsBeingDragged && yDiff > mTouchSlop && yDiff > xDiff) {
+ final float touchSlop = getTouchSlop(ev);
+ if (!mIsBeingDragged && yDiff > touchSlop && yDiff > xDiff) {
setIsBeingDragged(true);
if (deltaY > 0) {
- deltaY -= mTouchSlop;
+ deltaY -= touchSlop;
} else {
- deltaY += mTouchSlop;
+ deltaY += touchSlop;
}
}
if (mIsBeingDragged) {
@@ -4046,9 +4056,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public boolean onInterceptTouchEvent(MotionEvent ev) {
initDownStates(ev);
handleEmptySpaceClick(ev);
+
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
boolean expandWantsIt = false;
boolean swipingInProgress = mSwipingInProgress;
- if (!swipingInProgress && !mOnlyScrollingInThisMotion) {
+ if (!swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
}
boolean scrollWantsIt = false;
@@ -4065,7 +4077,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
// Check if we need to clear any snooze leavebehinds
boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
!expandWantsIt && !scrollWantsIt) {
mCheckForLeavebehind = false;
@@ -4083,8 +4094,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private void handleEmptySpaceClick(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
- if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
- || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop)) {
+ final float touchSlop = getTouchSlop(ev);
+ if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > touchSlop
+ || Math.abs(ev.getX() - mInitialTouchX) > touchSlop)) {
mTouchIsClick = false;
}
break;
@@ -4168,7 +4180,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
final int x = (int) ev.getX(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
final int xDiff = Math.abs(x - mDownX);
- if (yDiff > mTouchSlop && yDiff > xDiff) {
+ if (yDiff > getTouchSlop(ev) && yDiff > xDiff) {
setIsBeingDragged(true);
mLastMotionY = y;
mDownX = x;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f9726d2d77f9..5588c24f2fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1021,7 +1021,8 @@ public class NotificationPanelViewController extends PanelViewController {
trackMovement(event);
return true;
}
- if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+ if (Math.abs(h) > getTouchSlop(event)
+ && Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
mQsTracking = true;
onQsExpansionStarted();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2719a3278d24..481401b3eb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -30,8 +30,6 @@ public abstract class PanelView extends FrameLayout {
protected StatusBar mStatusBar;
protected HeadsUpManagerPhone mHeadsUpManager;
- protected int mTouchSlop;
-
protected KeyguardBottomAreaView mKeyguardBottomArea;
private OnConfigurationChangedListener mOnConfigurationChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 30367ed026ac..83cc4e33e2db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -91,7 +91,8 @@ public abstract class PanelViewController {
protected boolean mTracking;
private boolean mTouchSlopExceeded;
private int mTrackingPointer;
- protected int mTouchSlop;
+ private int mTouchSlop;
+ private float mSlopMultiplier;
protected boolean mHintAnimationRunning;
private boolean mOverExpandedBeforeFling;
private boolean mTouchAboveFalsingThreshold;
@@ -260,11 +261,19 @@ public abstract class PanelViewController {
protected void loadDimens() {
final ViewConfiguration configuration = ViewConfiguration.get(mView.getContext());
mTouchSlop = configuration.getScaledTouchSlop();
+ mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
mUnlockFalsingThreshold = mResources.getDimensionPixelSize(
R.dimen.unlock_falsing_threshold);
}
+ protected float getTouchSlop(MotionEvent event) {
+ // Adjust the touch slop if another gesture may be being performed.
+ return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mTouchSlop * mSlopMultiplier
+ : mTouchSlop;
+ }
+
private void addMovement(MotionEvent event) {
// Add movement to velocity tracker using raw screen X and Y coordinates instead
// of window coordinates because the window frame may be moving at the same time.
@@ -1111,7 +1120,8 @@ public abstract class PanelViewController {
addMovement(event);
if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) {
float hAbs = Math.abs(h);
- if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop))
+ float touchSlop = getTouchSlop(event);
+ if ((h < -touchSlop || (mAnimatingOnDown && hAbs > touchSlop))
&& hAbs > Math.abs(x - mInitialTouchX)) {
cancelHeightAnimator();
startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
@@ -1228,7 +1238,8 @@ public abstract class PanelViewController {
// If the panel was collapsed when touching, we only need to check for the
// y-component of the gesture, as we have no conflicting horizontal gesture.
- if (Math.abs(h) > mTouchSlop && (Math.abs(h) > Math.abs(x - mInitialTouchX)
+ if (Math.abs(h) > getTouchSlop(event)
+ && (Math.abs(h) > Math.abs(x - mInitialTouchX)
|| mIgnoreXTouchSlop)) {
mTouchSlopExceeded = true;
if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 1c1e7c4eaa4a..977a307a3d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -66,7 +66,7 @@ public class PhoneStatusBarView extends PanelBar {
}
};
private DarkReceiver mBattery;
- private int mRotationOrientation;
+ private int mRotationOrientation = -1;
@Nullable
private View mCenterIconSpace;
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 760a6d6a71c3..c6f79831e022 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -99,11 +99,12 @@ public class StatusBarWindowView extends FrameLayout {
}
// padding needed for corner cutout.
- int leftCornerCutoutPadding = 0;
- int rightCornerCutoutPadding = 0;
+ int leftCornerCutoutPadding = cutout.getSafeInsetLeft();
+ int rightCornerCutoutPadding = cutout.getSafeInsetRight();
if (cornerCutoutPadding != null) {
- leftCornerCutoutPadding = cornerCutoutPadding.first;
- rightCornerCutoutPadding = cornerCutoutPadding.second;
+ leftCornerCutoutPadding = Math.max(leftCornerCutoutPadding, cornerCutoutPadding.first);
+ rightCornerCutoutPadding = Math.max(rightCornerCutoutPadding,
+ cornerCutoutPadding.second);
}
return new Pair<>(
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index b54ec4ea9441..0fdabd09f9d4 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -21,13 +21,17 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IClassificationsCallback;
import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.contentsuggestions.ISelectionsCallback;
import android.app.contentsuggestions.SelectionsRequest;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
@@ -133,7 +137,7 @@ public class ContentSuggestionsManagerService extends
if (service != null) {
// TODO(b/147324195): Temporarily pass bitmap until we change the service API.
imageContextRequestExtras.putParcelable(EXTRA_BITMAP, bitmap);
- service.provideContextImageLocked(/* taskId = */ -1, imageContextRequestExtras);
+ service.provideContextImageFromBitmapLocked(imageContextRequestExtras);
} else {
if (VERBOSE) {
Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
@@ -152,10 +156,28 @@ public class ContentSuggestionsManagerService extends
}
enforceCaller(UserHandle.getCallingUserId(), "provideContextImage");
+ GraphicBuffer snapshotBuffer = null;
+ int colorSpaceId = 0;
+
+ // Skip taking TaskSnapshot when bitmap is provided.
+ if (!imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
+ // Can block, so call before acquiring the lock.
+ ActivityManager.TaskSnapshot snapshot =
+ mActivityTaskManagerInternal.getTaskSnapshotBlocking(taskId, false);
+ if (snapshot != null) {
+ snapshotBuffer = snapshot.getSnapshot();
+ ColorSpace colorSpace = snapshot.getColorSpace();
+ if (colorSpace != null) {
+ colorSpaceId = colorSpace.getId();
+ }
+ }
+ }
+
synchronized (mLock) {
final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
if (service != null) {
- service.provideContextImageLocked(taskId, imageContextRequestExtras);
+ service.provideContextImageLocked(taskId, snapshotBuffer, colorSpaceId,
+ imageContextRequestExtras);
} else {
if (VERBOSE) {
Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
index 7828050223f4..cf53b169515e 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -19,17 +19,14 @@ package com.android.server.contentsuggestions;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.contentsuggestions.ClassificationsRequest;
-import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IClassificationsCallback;
import android.app.contentsuggestions.ISelectionsCallback;
import android.app.contentsuggestions.SelectionsRequest;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
-import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.os.Bundle;
import android.os.RemoteException;
@@ -95,26 +92,17 @@ public final class ContentSuggestionsPerUserService extends
}
@GuardedBy("mLock")
- void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
+ void provideContextImageFromBitmapLocked(@NonNull Bundle bitmapContainingExtras) {
+ // No task or snapshot provided, the bitmap is contained in the extras
+ provideContextImageLocked(-1, null, 0, bitmapContainingExtras);
+ }
+
+ @GuardedBy("mLock")
+ void provideContextImageLocked(int taskId, @Nullable GraphicBuffer snapshot,
+ int colorSpaceIdForSnapshot, @NonNull Bundle imageContextRequestExtras) {
RemoteContentSuggestionsService service = ensureRemoteServiceLocked();
if (service != null) {
- GraphicBuffer snapshotBuffer = null;
- int colorSpaceId = 0;
-
- // Skip taking TaskSnapshot when bitmap is provided.
- if (!imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
- ActivityManager.TaskSnapshot snapshot =
- mActivityTaskManagerInternal.getTaskSnapshotNoRestore(taskId, false);
- if (snapshot != null) {
- snapshotBuffer = snapshot.getSnapshot();
- ColorSpace colorSpace = snapshot.getColorSpace();
- if (colorSpace != null) {
- colorSpaceId = colorSpace.getId();
- }
- }
- }
-
- service.provideContextImage(taskId, snapshotBuffer, colorSpaceId,
+ service.provideContextImage(taskId, snapshot, colorSpaceIdForSnapshot,
imageContextRequestExtras);
}
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 9b04e7931f7c..fe33fae98306 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1876,7 +1876,7 @@ class AlarmManagerService extends SystemService {
// package was t(q) then the next delivery must be after t(q) + <window_size>
final long t = mAppWakeupHistory.getNthLastWakeupForPackage(
sourcePackage, sourceUserId, quotaForBucket);
- minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
+ minElapsed = t + mConstants.APP_STANDBY_WINDOW;
}
if (alarm.expectedWhenElapsed < minElapsed) {
alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index cea3251d26a1..3148a6205871 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -103,7 +103,7 @@ public final class PinnerService extends SystemService {
private static boolean PROP_PIN_CAMERA =
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
"pin_camera",
- SystemProperties.getBoolean("pinner.pin_camera", true));
+ SystemProperties.getBoolean("pinner.pin_camera", false));
// Pin using pinlist.meta when pinning apps.
private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
"pinner.use_pinlist", true);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1f0146ad815d..ada3e4269f6a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4570,6 +4570,7 @@ public class AudioService extends IAudioService.Stub
public void setWiredDeviceConnectionState(int type,
@ConnectionState int state, String address, String name,
String caller) {
+ enforceModifyAudioRoutingPermission();
if (state != CONNECTION_STATE_CONNECTED
&& state != CONNECTION_STATE_DISCONNECTED) {
throw new IllegalArgumentException("Invalid state " + state);
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index e5cb5540b781..054f5defd549 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -15,9 +15,7 @@
*/
package com.android.server.notification;
-import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.FLAG_BUBBLE;
-import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
@@ -25,7 +23,6 @@ import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR
import android.app.ActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
-import android.app.Person;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -34,8 +31,6 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import java.util.ArrayList;
-
/**
* Determines whether a bubble can be shown for this notification
*/
@@ -152,41 +147,13 @@ public class BubbleExtractor implements NotificationSignalExtractor {
return false;
}
- // At this point the bubble must fulfill communication policy
-
- // Communication always needs a person
- ArrayList<Person> peopleList = notification.extras != null
- ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
- : null;
- // Message style requires a person & it's not included in the list
boolean isMessageStyle = Notification.MessagingStyle.class.equals(
notification.getNotificationStyle());
- if (!isMessageStyle && (peopleList == null || peopleList.isEmpty())) {
- logBubbleError(r.getKey(), "Must have a person and be "
- + "Notification.MessageStyle or Notification.CATEGORY_CALL");
+ if (!isMessageStyle) {
+ logBubbleError(r.getKey(), "must be Notification.MessageStyle");
return false;
}
-
- // Communication is a message or a call
- boolean isCall = CATEGORY_CALL.equals(notification.category);
- boolean hasForegroundService = (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
- if (hasForegroundService && !isCall) {
- logBubbleError(r.getKey(),
- "foreground services must be Notification.CATEGORY_CALL to bubble");
- return false;
- }
- if (isMessageStyle) {
- return true;
- } else if (isCall) {
- if (hasForegroundService) {
- return true;
- }
- logBubbleError(r.getKey(), "calls require foreground service");
- return false;
- }
- logBubbleError(r.getKey(), "Must be "
- + "Notification.MessageStyle or Notification.CATEGORY_CALL");
- return false;
+ return true;
}
/**
@@ -218,7 +185,7 @@ public class BubbleExtractor implements NotificationSignalExtractor {
String shortcutId = metadata.getShortcutId();
boolean shortcutValid = shortcutId != null
- && mShortcutHelper.hasValidShortcutInfo(shortcutId, pkg, r.getUser());
+ && mShortcutHelper.getValidShortcutInfo(shortcutId, pkg, r.getUser()) != null;
if (metadata.getIntent() == null && !shortcutValid) {
// Should have a shortcut if intent is null
logBubbleError(r.getKey(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f65f187eddc5..60c387528c6a 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -243,7 +243,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
@@ -3454,7 +3453,7 @@ public class NotificationManagerService extends SystemService {
ArrayList<ConversationChannelWrapper> conversations =
mPreferencesHelper.getConversations(onlyImportant);
for (ConversationChannelWrapper conversation : conversations) {
- conversation.setShortcutInfo(mShortcutHelper.getShortcutInfo(
+ conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
conversation.getNotificationChannel().getConversationId(),
conversation.getPkg(),
UserHandle.of(UserHandle.getUserId(conversation.getUid()))));
@@ -3477,7 +3476,7 @@ public class NotificationManagerService extends SystemService {
ArrayList<ConversationChannelWrapper> conversations =
mPreferencesHelper.getConversations(pkg, uid);
for (ConversationChannelWrapper conversation : conversations) {
- conversation.setShortcutInfo(mShortcutHelper.getShortcutInfo(
+ conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
conversation.getNotificationChannel().getConversationId(),
pkg,
UserHandle.of(UserHandle.getUserId(uid))));
@@ -3639,13 +3638,23 @@ public class NotificationManagerService extends SystemService {
}
/**
+ * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead.
+ */
+ @Deprecated
+ @Override
+ public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+ return getActiveNotificationsWithAttribution(callingPkg, null);
+ }
+
+ /**
* System-only API for getting a list of current (i.e. not cleared) notifications.
*
* Requires ACCESS_NOTIFICATIONS which is signature|system.
* @returns A list of all the notifications, in natural order.
*/
@Override
- public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+ public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg,
+ String callingAttributionTag) {
// enforce() will ensure the calling uid has the correct permission
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -3655,7 +3664,8 @@ public class NotificationManagerService extends SystemService {
int uid = Binder.getCallingUid();
// noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
+ callingAttributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
synchronized (mNotificationLock) {
tmp = new StatusBarNotification[mNotificationList.size()];
@@ -3737,12 +3747,24 @@ public class NotificationManagerService extends SystemService {
}
/**
- * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+ * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead.
*/
+ @Deprecated
@Override
@RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count,
boolean includeSnoozed) {
+ return getHistoricalNotificationsWithAttribution(callingPkg, null, count,
+ includeSnoozed);
+ }
+
+ /**
+ * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+ */
+ @Override
+ @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
+ public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg,
+ String callingAttributionTag, int count, boolean includeSnoozed) {
// enforce() will ensure the calling uid has the correct permission
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -3752,7 +3774,8 @@ public class NotificationManagerService extends SystemService {
int uid = Binder.getCallingUid();
// noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
+ callingAttributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
synchronized (mArchive) {
tmp = mArchive.getArray(count, includeSnoozed);
@@ -3768,7 +3791,8 @@ public class NotificationManagerService extends SystemService {
@Override
@WorkerThread
@RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
- public NotificationHistory getNotificationHistory(String callingPkg) {
+ public NotificationHistory getNotificationHistory(String callingPkg,
+ String callingAttributionTag) {
// enforce() will ensure the calling uid has the correct permission
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -3776,7 +3800,8 @@ public class NotificationManagerService extends SystemService {
int uid = Binder.getCallingUid();
// noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
+ callingAttributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory");
@@ -5648,7 +5673,8 @@ public class NotificationManagerService extends SystemService {
}
}
- r.setShortcutInfo(mShortcutHelper.getShortcutInfo(notification.getShortcutId(), pkg, user));
+ r.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
+ notification.getShortcutId(), pkg, user));
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
r.getSbn().getOverrideGroupKey() != null)) {
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 7bbb3b117517..f1ce3a7d9f48 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -121,7 +121,10 @@ class ShortcutHelper {
mLauncherAppsService = launcherApps;
}
- ShortcutInfo getShortcutInfo(String shortcutId, String packageName, UserHandle user) {
+ /**
+ * Only returns shortcut info if it's found and if it's {@link ShortcutInfo#isLongLived()}.
+ */
+ ShortcutInfo getValidShortcutInfo(String shortcutId, String packageName, UserHandle user) {
if (mLauncherAppsService == null) {
return null;
}
@@ -135,20 +138,15 @@ class ShortcutHelper {
query.setShortcutIds(Arrays.asList(shortcutId));
query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED);
List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user);
- return shortcuts != null && shortcuts.size() > 0
+ ShortcutInfo info = shortcuts != null && shortcuts.size() > 0
? shortcuts.get(0)
: null;
+ return info != null && info.isLongLived() ? info : null;
} finally {
Binder.restoreCallingIdentity(token);
}
}
- boolean hasValidShortcutInfo(String shortcutId, String packageName,
- UserHandle user) {
- ShortcutInfo shortcutInfo = getShortcutInfo(shortcutId, packageName, user);
- return shortcutInfo != null && shortcutInfo.isLongLived();
- }
-
/**
* Shortcut based bubbles require some extra work to listen for shortcut changes.
*
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b79f75a2d335..4e5d6c4efaab 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -161,6 +161,7 @@ import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
+import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
@@ -178,6 +179,7 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
+import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -812,6 +814,10 @@ public class PackageManagerService extends IPackageManager.Stub
private final OverlayConfig mOverlayConfig;
+ @GuardedBy("itself")
+ final private ArrayList<IPackageChangeObserver> mPackageChangeObservers =
+ new ArrayList<>();
+
/**
* Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
*
@@ -16458,9 +16464,56 @@ public class PackageManagerService extends IPackageManager.Stub
// BackgroundDexOptService will remove it from its blacklist.
// TODO: Layering violation
BackgroundDexOptService.notifyPackageChanged(packageName);
+
+ notifyPackageChangeObserversOnUpdate(reconciledPkg);
}
}
+ private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
+ final PackageSetting pkgSetting = reconciledPkg.pkgSetting;
+ final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult;
+ final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.removedInfo;
+
+ PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+ pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName();
+ pkgChangeEvent.version = pkgSetting.versionCode;
+ pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime;
+ pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.isUpdate);
+ pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.dataRemoved);
+ pkgChangeEvent.isDeleted = false;
+
+ notifyPackageChangeObservers(pkgChangeEvent);
+ }
+
+ private void notifyPackageChangeObserversOnDelete(String packageName, long version) {
+ PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+ pkgChangeEvent.packageName = packageName;
+ pkgChangeEvent.version = version;
+ pkgChangeEvent.lastUpdateTimeMillis = 0L;
+ pkgChangeEvent.newInstalled = false;
+ pkgChangeEvent.dataRemoved = false;
+ pkgChangeEvent.isDeleted = true;
+
+ notifyPackageChangeObservers(pkgChangeEvent);
+ }
+
+ private void notifyPackageChangeObservers(PackageChangeEvent event) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
+ synchronized (mPackageChangeObservers) {
+ for(IPackageChangeObserver observer : mPackageChangeObservers) {
+ try {
+ observer.onPackageChanged(event);
+ } catch(RemoteException e) {
+ Log.wtf(TAG, e);
+ }
+ }
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
/**
* The set of data needed to successfully install the prepared package. This includes data that
* will be used to scan and reconcile the package.
@@ -17521,6 +17574,7 @@ public class PackageManagerService extends IPackageManager.Stub
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
} //end catch
+ notifyPackageChangeObserversOnDelete(packageName, versionCode);
});
}
@@ -22980,8 +23034,49 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
+ private final IPackageChangeObserver mObserver;
+
+ PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) {
+ mObserver = observer;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mPackageChangeObservers) {
+ mPackageChangeObservers.remove(mObserver);
+ Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is "
+ + mPackageChangeObservers.size());
+ }
+ }
+ }
+
private class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
+ public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
+ synchronized (mPackageChangeObservers) {
+ try {
+ observer.asBinder().linkToDeath(
+ new PackageChangeObserverDeathRecipient(observer), 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mPackageChangeObservers.add(observer);
+ Log.d(TAG, "Size of mPackageChangeObservers after registry is "
+ + mPackageChangeObservers.size());
+ }
+ }
+
+ @Override
+ public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
+ synchronized (mPackageChangeObservers) {
+ mPackageChangeObservers.remove(observer);
+ Log.d(TAG, "Size of mPackageChangeObservers after unregistry is "
+ + mPackageChangeObservers.size());
+ }
+ }
+
+ @Override
public String[] getAllPackages() {
return PackageManagerService.this.getAllPackages().toArray(new String[0]);
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 63048f6b95b3..a83ba97b3baf 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -377,7 +377,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
mCallback = callback;
mHandle = handle;
try {
- mCallback.asBinder().linkToDeath(null, 0);
+ mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -680,7 +680,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
try {
mDelegate.detach();
mDelegate = null;
- mCallback.asBinder().unlinkToDeath(null, 0);
+ mCallback.asBinder().unlinkToDeath(this, 0);
mModules.get(mHandle).remove(this);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index edc87e5a4d88..2263795f9442 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -548,8 +548,11 @@ public abstract class ActivityTaskManagerInternal {
/**
* Gets bitmap snapshot of the provided task id.
+ *
+ * <p>Warning! this may restore the snapshot from disk so can block, don't call in a latency
+ * sensitive environment.
*/
- public abstract ActivityManager.TaskSnapshot getTaskSnapshotNoRestore(int taskId,
+ public abstract ActivityManager.TaskSnapshot getTaskSnapshotBlocking(int taskId,
boolean isLowResolution);
/** Returns true if uid is considered foreground for activity start purposes. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f7278e70cede..214a6767f3b2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7477,10 +7477,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public ActivityManager.TaskSnapshot getTaskSnapshotNoRestore(int taskId,
- boolean isLowResolution) {
+ public ActivityManager.TaskSnapshot getTaskSnapshotBlocking(
+ int taskId, boolean isLowResolution) {
return ActivityTaskManagerService.this.getTaskSnapshot(taskId, isLowResolution,
- false /* restoreFromDisk */);
+ true /* restoreFromDisk */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 55dc694bb611..cd4fb3dc7691 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -129,11 +129,11 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.window.ITaskOrganizer;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.window.ITaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
@@ -578,6 +578,14 @@ class Task extends WindowContainer<WindowContainer> {
voiceInteractor = _voiceInteractor;
setIntent(activity, intent, info);
setMinDimensions(info);
+ // Before we began to reuse a root task (old ActivityStack) as the leaf task, we used to
+ // create a leaf task in this case. Therefore now we won't send out the task created
+ // notification when we decide to reuse it here, so we send out the notification below.
+ // The reason why the created notification sent out when root task is created doesn't work
+ // is that realActivity isn't set until setIntent() method above is called for the first
+ // time. Eventually this notification will be removed when we can populate those information
+ // when root task is created.
+ mAtmService.getTaskChangeNotificationController().notifyTaskCreated(mTaskId, realActivity);
return this;
}
@@ -586,11 +594,7 @@ class Task extends WindowContainer<WindowContainer> {
return;
}
- // TODO(xutan): Removed type check after stack and task is merged.
- // Before the real merge of stack and task, we need to avoid saving state of stacks. Once
- // the merge is finished we can just pass DisplayContent because both windowing mode and
- // bounds are set in the merged task.
- if (oldParent instanceof ActivityStack) {
+ if (isLeafTask()) {
// This task is going away, so save the last state if necessary.
saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index bb149cf327b8..09af4421406d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -496,7 +496,7 @@ public class AlarmManagerServiceTest {
// This one should get deferred on set
setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
getNewMockPendingIntent());
- final long expectedNextTrigger = firstTrigger + 1 + mAppStandbyWindow;
+ final long expectedNextTrigger = firstTrigger + mAppStandbyWindow;
assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
}
@@ -516,7 +516,7 @@ public class AlarmManagerServiceTest {
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
}
- final long expectedNextTrigger = firstTrigger + 1 + mAppStandbyWindow;
+ final long expectedNextTrigger = firstTrigger + mAppStandbyWindow;
assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
}
@@ -676,7 +676,7 @@ public class AlarmManagerServiceTest {
final int rareQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_RARE);
// The last alarm should now be deferred.
final long expectedNextTrigger = (firstTrigger + workingQuota - 1 - rareQuota)
- + mAppStandbyWindow + 1;
+ + mAppStandbyWindow;
assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
}
@@ -695,7 +695,7 @@ public class AlarmManagerServiceTest {
}
}
// The last alarm should be deferred due to exceeding the quota
- final long deferredTrigger = firstTrigger + 1 + mAppStandbyWindow;
+ final long deferredTrigger = firstTrigger + mAppStandbyWindow;
assertEquals(deferredTrigger, mTestTimer.getElapsed());
// Upgrading the bucket now
@@ -730,7 +730,7 @@ public class AlarmManagerServiceTest {
mTestTimer.expire();
}
// Any subsequent alarms in queue should all be deferred
- assertEquals(firstTrigger + mAppStandbyWindow + 1, mTestTimer.getElapsed());
+ assertEquals(firstTrigger + mAppStandbyWindow, mTestTimer.getElapsed());
// Paroling now
assertAndHandleParoleChanged(true);
@@ -744,7 +744,7 @@ public class AlarmManagerServiceTest {
assertAndHandleParoleChanged(false);
// Subsequent alarms should again get deferred
- final long expectedNextTrigger = (firstTrigger + 5) + 1 + mAppStandbyWindow;
+ final long expectedNextTrigger = (firstTrigger + 5) + mAppStandbyWindow;
assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java
index d7fc97c8722d..2578ca892520 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -33,6 +34,7 @@ import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -110,8 +112,10 @@ public class BubbleCheckerTest extends UiServiceTestCase {
void setUpShortcutBubble(boolean isValid) {
when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID);
- when(mShortcutHelper.hasValidShortcutInfo(SHORTCUT_ID, PKG, mUserHandle))
- .thenReturn(isValid);
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getId()).thenReturn(SHORTCUT_ID);
+ when(mShortcutHelper.getValidShortcutInfo(SHORTCUT_ID, PKG, mUserHandle))
+ .thenReturn(isValid ? info : null);
when(mBubbleMetadata.getIntent()).thenReturn(null);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9db7d5e3acdd..d2417f9d10c5 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -18,7 +18,6 @@ package com.android.server.notification;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
-import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
@@ -5237,141 +5236,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testFlagBubbleNotifs_flag_phonecall() throws RemoteException {
- // Bubbles are allowed!
- setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Give it a person
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- // Make it a phone call
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setCategory(CATEGORY_CALL)
- .addPerson(person)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testFlagBubbleNotifs_flag_phonecall", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- // Make sure it has foreground service
- sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- // yes phone call, yes person, yes foreground service, yes bubble
- assertTrue(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
- public void testFlagBubbleNotifs_noFlag_phonecall_noForegroundService() throws RemoteException {
- // Bubbles are allowed!
- setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Give it a person
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- // Make it a phone call
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setCategory(CATEGORY_CALL)
- .addPerson(person)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- // yes phone call, yes person, NO foreground service, no bubble
- assertFalse(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
- public void testFlagBubbleNotifs_noFlag_phonecall_noPerson() throws RemoteException {
- // Bubbles are allowed!
- setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Make it a phone call
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setCategory(CATEGORY_CALL)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testFlagBubbleNotifs_noFlag_phonecall_noPerson", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- // Make sure it has foreground service
- sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- // yes phone call, yes foreground service, BUT NO person, no bubble
- assertFalse(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
- public void testFlagBubbleNotifs_noFlag_phonecall_noCategory() throws RemoteException {
- // Bubbles are allowed!
- setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Give it a person
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- // No category
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .addPerson(person)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testFlagBubbleNotifs_noFlag_phonecall_noCategory", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- // Make sure it has foreground service
- sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- // yes person, yes foreground service, BUT NO call, no bubble
- assertFalse(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException {
// Bubbles are NOT allowed!
setUpPrefsForBubbles(PKG, mUid, true /* global */, false /* app */, true /* channel */);
@@ -5432,77 +5296,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testFlagBubbleNotifs_noFlag_phonecall_notAllowed() throws RemoteException {
- // Bubbles are not allowed!
- setUpPrefsForBubbles(PKG, mUid, false /* global */, true /* app */, true /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Give it a person
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- // Make it a phone call
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setCategory(CATEGORY_CALL)
- .addPerson(person)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testFlagBubbleNotifs_noFlag_phonecall_notAllowed", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- // Make sure it has foreground service
- sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
- sbn.getId(), sbn.getNotification(), sbn.getUserId());
- waitForIdle();
-
- // yes phone call, yes person, yes foreground service, but not allowed, no bubble
- assertFalse(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
- public void testFlagBubbleNotifs_noFlag_phonecall_channelNotAllowed() throws RemoteException {
- // Bubbles are allowed, but not on channel.
- setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, false /* channel */);
-
- // Give it bubble metadata
- Notification.BubbleMetadata data = getBubbleMetadataBuilder().build();
- // Give it a person
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- // Make it a phone call
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setCategory(CATEGORY_CALL)
- .addPerson(person)
- .setContentTitle("foo")
- .setBubbleMetadata(data)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testFlagBubbleNotifs_noFlag_phonecall_channelNotAllowed", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
- // Make sure it has foreground service
- sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- // yes phone call, yes person, yes foreground service, but channel not allowed, no bubble
- assertFalse(mService.getNotificationRecord(
- sbn.getKey()).getNotification().isBubbleNotification());
- }
-
- @Test
public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception {
final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
@@ -6579,13 +6372,41 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
ShortcutInfo si = mock(ShortcutInfo.class);
when(si.getShortLabel()).thenReturn("Hello");
+ when(si.isLongLived()).thenReturn(true);
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
List<ConversationChannelWrapper> conversations =
mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
assertEquals(si, conversations.get(0).getShortcutInfo());
assertEquals(si, conversations.get(1).getShortcutInfo());
+ }
+ @Test
+ public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+ ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
+ ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
+ NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
+ channel1.setConversationId("parent1", "convo 1");
+ convo1.setNotificationChannel(channel1);
+ convos.add(convo1);
+
+ ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
+ NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
+ channel2.setConversationId("parent1", "convo 2");
+ convo2.setNotificationChannel(channel2);
+ convos.add(convo2);
+ when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
+
+ ShortcutInfo si = mock(ShortcutInfo.class);
+ when(si.getShortLabel()).thenReturn("Hello");
+ when(si.isLongLived()).thenReturn(false);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
+
+ List<ConversationChannelWrapper> conversations =
+ mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
+ assertNull(conversations.get(0).getShortcutInfo());
+ assertNull(conversations.get(1).getShortcutInfo());
}
@Test
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 2f9a1c8ade0d..9be97b505a3f 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -509,16 +509,68 @@ public class AppLaunch extends InstrumentationTestCase {
for (int i = 0; i < IORAP_COMPILE_CMD_TIMEOUT; ++i) {
IorapCompilationStatus status = waitForIorapCompiled(appPkgName);
if (status == IorapCompilationStatus.COMPLETE) {
+ Log.v(TAG, "compileAppForIorap: success");
+ logDumpsysIorapd(appPkgName);
return true;
} else if (status == IorapCompilationStatus.INSUFFICIENT_TRACES) {
+ Log.e(TAG, "compileAppForIorap: failed due to insufficient traces");
+ logDumpsysIorapd(appPkgName);
return false;
} // else INCOMPLETE. keep asking iorapd if it's done yet.
sleep(1000);
}
+ Log.e(TAG, "compileAppForIorap: failed due to timeout");
+ logDumpsysIorapd(appPkgName);
return false;
}
+ /** Save the contents of $(adb shell dumpsys iorapd) to the launch_logs directory. */
+ private void logDumpsysIorapd(String packageName) throws IOException {
+ InstrumentationTestRunner instrumentation =
+ (InstrumentationTestRunner)getInstrumentation();
+ Bundle args = instrumentation.getArguments();
+
+ String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
+
+ // Root directory for applaunch file to log the app launch output
+ // Will be useful in case of simpleperf command is used
+ File launchRootDir = null;
+ if (null != launchDirectory && !launchDirectory.isEmpty()) {
+ launchRootDir = new File(launchDirectory);
+ if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
+ throw new IOException("Unable to create the destination directory "
+ + launchRootDir + ". Try disabling selinux.");
+ }
+ } else {
+ Log.w(TAG, "logDumpsysIorapd: Missing launch-directory arg");
+ return;
+ }
+
+ File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
+ if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
+ throw new IOException("Unable to create the lauch file sub directory "
+ + launchSubDir + ". Try disabling selinux.");
+ }
+ String path = "iorapd_dumpsys_" + packageName + "_" + System.nanoTime() + ".txt";
+ File file = new File(launchSubDir, path);
+ try (FileOutputStream outputStream = new FileOutputStream(file);
+ BufferedWriter writer = new BufferedWriter(
+ new OutputStreamWriter(outputStream));
+ ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+ executeShellCommand(IORAP_DUMPSYS_CMD);
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ writer.write(line + "\n");
+ }
+ }
+
+ Log.v(TAG, "logDumpsysIorapd: Saved to file: " + path);
+ }
+
enum IorapCompilationStatus {
INCOMPLETE,
COMPLETE,
diff --git a/tests/BootImageProfileTest/AndroidTest.xml b/tests/BootImageProfileTest/AndroidTest.xml
index d7f820411f27..7e97fa3a8ff1 100644
--- a/tests/BootImageProfileTest/AndroidTest.xml
+++ b/tests/BootImageProfileTest/AndroidTest.xml
@@ -23,6 +23,10 @@
<option name="force-skip-system-props" value="true" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.bootimageprofile.BootImageProfileTest" />
</test>
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
index 548af0c54b03..498cb7c1c710 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -18,7 +18,6 @@ package com.google.android.test.windowinsetstests;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
-
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -31,6 +30,7 @@ import android.content.Context;
import android.graphics.Insets;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -44,11 +44,11 @@ import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
-import androidx.appcompat.app.AppCompatActivity;
-
import java.util.ArrayList;
import java.util.List;
+import androidx.appcompat.app.AppCompatActivity;
+
public class WindowInsetsActivity extends AppCompatActivity {
private View mRoot;
@@ -191,6 +191,40 @@ public class WindowInsetsActivity extends AppCompatActivity {
mTransitions.forEach(it -> it.onFinish(animation));
}
});
+
+ findViewById(R.id.floating_action_button).setOnClickListener(
+ v -> v.getWindowInsetsController().controlWindowInsetsAnimation(ime(), -1,
+ new LinearInterpolator(), null /* cancellationSignal */,
+ new WindowInsetsAnimationControlListener() {
+ @Override
+ public void onReady(
+ WindowInsetsAnimationController controller,
+ int types) {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setDuration(1500);
+ anim.addUpdateListener(animation
+ -> controller.setInsetsAndAlpha(
+ controller.getShownStateInsets(),
+ (float) animation.getAnimatedValue(),
+ anim.getAnimatedFraction()));
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ controller.finish(true);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
+ public void onCancelled(WindowInsetsAnimationController controller) {
+ }
+
+ @Override
+ public void onFinished(WindowInsetsAnimationController controller) {
+ }
+ }));
}
@Override
@@ -200,57 +234,6 @@ public class WindowInsetsActivity extends AppCompatActivity {
getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false));
}
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- getWindow().getInsetsController().addOnControllableInsetsChangedListener(
- new OnControllableInsetsChangedListener() {
-
- boolean hasControl = false;
- @Override
- public void onControllableInsetsChanged(WindowInsetsController controller,
- int types) {
- if ((types & ime()) != 0 && !hasControl) {
- hasControl = true;
- controller.controlWindowInsetsAnimation(ime(), -1,
- new LinearInterpolator(), null /* cancellationSignal */,
- new WindowInsetsAnimationControlListener() {
- @Override
- public void onReady(
- WindowInsetsAnimationController controller,
- int types) {
- ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
- anim.setDuration(1500);
- anim.addUpdateListener(animation
- -> controller.setInsetsAndAlpha(
- controller.getShownStateInsets(),
- (float) animation.getAnimatedValue(),
- anim.getAnimatedFraction()));
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- controller.finish(true);
- }
- });
- anim.start();
- }
-
- @Override
- public void onFinished(
- WindowInsetsAnimationController controller) {
- }
-
- @Override
- public void onCancelled(
- WindowInsetsAnimationController controller) {
- }
- });
- }
- }
- });
- }
-
static class Transition {
private int mEndBottom;
private int mStartBottom;
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 34e2e3af9cda..ea5043ae5f65 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -30,5 +30,9 @@
<object type="module_controller"
class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
<option name="mainline-module-package-name" value="com.google.android.wifi" />
+ <!-- TODO(b/151836001): com.android.wifi doesn't guarantee it is a Mainline module since
+ it could still be OEM customized. Workaround so that this test will still run on
+ AOSP builds. -->
+ <option name="mainline-module-package-name" value="com.android.wifi" />
</object>
</configuration>