diff options
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 >= 1.0 >= 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 Binary files differnew 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 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 Binary files differnew file mode 100644 index 000000000000..4ab9ca4fa580 --- /dev/null +++ b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png 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 Binary files differnew file mode 100644 index 000000000000..d74e673a9ce1 --- /dev/null +++ b/docs/html/reference/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png 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> |