diff options
Diffstat (limited to 'cmds')
124 files changed, 6431 insertions, 3381 deletions
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index ed717c491467..4b7eda096e54 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -19,6 +19,7 @@ package com.android.commands.bmgr; import android.annotation.IntDef; import android.annotation.UserIdInt; import android.app.backup.BackupManager; +import android.app.backup.BackupManager.OperationType; import android.app.backup.BackupManagerMonitor; import android.app.backup.BackupProgress; import android.app.backup.BackupTransport; @@ -666,7 +667,7 @@ public class Bmgr { // The rest of the 'list' options work with a restore session on the current transport try { - mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null); + mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP); if (mRestore == null) { System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId); return; @@ -821,7 +822,7 @@ public class Bmgr { try { boolean didRestore = false; - mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null); + mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP); if (mRestore == null) { System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId); return; diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp index 757c2b2a4cfa..0f569971ff62 100644 --- a/cmds/bootanimation/Android.bp +++ b/cmds/bootanimation/Android.bp @@ -60,7 +60,7 @@ cc_library_shared { shared_libs: [ "libui", - "libhwui", + "libjnigraphics", "libEGL", "libGLESv1_CM", "libgui", diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index bb2de17b42f3..9c796128df84 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -34,6 +34,7 @@ #include <cutils/atomic.h> #include <cutils/properties.h> +#include <android/imagedecoder.h> #include <androidfw/AssetManager.h> #include <binder/IPCThreadState.h> #include <utils/Errors.h> @@ -52,14 +53,6 @@ #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> -// TODO: Fix Skia. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <SkBitmap.h> -#include <SkImage.h> -#include <SkStream.h> -#pragma GCC diagnostic pop - #include <GLES/gl.h> #include <GLES/glext.h> #include <EGL/eglext.h> @@ -114,8 +107,8 @@ static constexpr size_t TEXT_POS_LEN_MAX = 16; // --------------------------------------------------------------------------- BootAnimation::BootAnimation(sp<Callbacks> callbacks) - : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeFormat12Hour(false), - mTimeCheckThread(nullptr), mCallbacks(callbacks), mLooper(new Looper(false)) { + : Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false), + mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) { mSession = new SurfaceComposerClient(); std::string powerCtl = android::base::GetProperty("sys.powerctl", ""); @@ -165,22 +158,51 @@ void BootAnimation::binderDied(const wp<IBinder>&) { requestExit(); } +static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) { + AImageDecoder* decoder = nullptr; + AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder); + if (!decoder) { + return nullptr; + } + + const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder); + outInfo->width = AImageDecoderHeaderInfo_getWidth(info); + outInfo->height = AImageDecoderHeaderInfo_getHeight(info); + outInfo->format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info); + outInfo->stride = AImageDecoder_getMinimumStride(decoder); + outInfo->flags = 0; + + const size_t size = outInfo->stride * outInfo->height; + void* pixels = malloc(size); + int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size); + AImageDecoder_delete(decoder); + + if (result != ANDROID_IMAGE_DECODER_SUCCESS) { + free(pixels); + return nullptr; + } + return pixels; +} + status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, const char* name) { Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); if (asset == nullptr) return NO_INIT; - SkBitmap bitmap; - sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false), - asset->getLength()); - sk_sp<SkImage> image = SkImage::MakeFromEncoded(data); - image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode); + + AndroidBitmapInfo bitmapInfo; + void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo); + auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free }; + asset->close(); delete asset; - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* p = bitmap.getPixels(); + if (!pixels) { + return NO_INIT; + } + + const int w = bitmapInfo.width; + const int h = bitmapInfo.height; GLint crop[4] = { 0, h, w, -h }; texture->w = w; @@ -189,22 +211,22 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, glGenTextures(1, &texture->name); glBindTexture(GL_TEXTURE_2D, texture->name); - switch (bitmap.colorType()) { - case kAlpha_8_SkColorType: + switch (bitmapInfo.format) { + case ANDROID_BITMAP_FORMAT_A_8: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, - GL_UNSIGNED_BYTE, p); + GL_UNSIGNED_BYTE, pixels); break; - case kARGB_4444_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_4444: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_SHORT_4_4_4_4, p); + GL_UNSIGNED_SHORT_4_4_4_4, pixels); break; - case kN32_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_8888: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, p); + GL_UNSIGNED_BYTE, pixels); break; - case kRGB_565_SkColorType: + case ANDROID_BITMAP_FORMAT_RGB_565: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, p); + GL_UNSIGNED_SHORT_5_6_5, pixels); break; default: break; @@ -220,20 +242,21 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, } status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { - SkBitmap bitmap; - sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(), - map->getDataLength()); - sk_sp<SkImage> image = SkImage::MakeFromEncoded(data); - image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode); + AndroidBitmapInfo bitmapInfo; + void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo); + auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free }; // FileMap memory is never released until application exit. // Release it now as the texture is already loaded and the memory used for // the packed resource can be released. delete map; - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* p = bitmap.getPixels(); + if (!pixels) { + return NO_INIT; + } + + const int w = bitmapInfo.width; + const int h = bitmapInfo.height; GLint crop[4] = { 0, h, w, -h }; int tw = 1 << (31 - __builtin_clz(w)); @@ -241,28 +264,28 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { if (tw < w) tw <<= 1; if (th < h) th <<= 1; - switch (bitmap.colorType()) { - case kN32_SkColorType: + switch (bitmapInfo.format) { + case ANDROID_BITMAP_FORMAT_RGBA_8888: if (!mUseNpotTextures && (tw != w || th != h)) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p); + 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, p); + GL_UNSIGNED_BYTE, pixels); } break; - case kRGB_565_SkColorType: + case ANDROID_BITMAP_FORMAT_RGB_565: if (!mUseNpotTextures && (tw != w || th != h)) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, nullptr); glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p); + 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels); } else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, p); + GL_UNSIGNED_SHORT_5_6_5, pixels); } break; default: @@ -394,7 +417,7 @@ status_t BootAnimation::readyToRun() { // this guest property specifies multi-display IDs to show the boot animation // multiple ids can be set with comma (,) as separator, for example: // setprop persist.boot.animation.displays 19260422155234049,19261083906282754 - Vector<uint64_t> physicalDisplayIds; + Vector<PhysicalDisplayId> physicalDisplayIds; char displayValue[PROPERTY_VALUE_MAX] = ""; property_get(DISPLAYS_PROP_NAME, displayValue, ""); bool isValid = displayValue[0] != '\0'; @@ -412,7 +435,7 @@ status_t BootAnimation::readyToRun() { } if (isValid) { std::istringstream stream(displayValue); - for (PhysicalDisplayId id; stream >> id; ) { + for (PhysicalDisplayId id; stream >> id.value; ) { physicalDisplayIds.add(id); if (stream.peek() == ',') stream.ignore(); diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 6ba7fd450fbb..9e6e4aa42f1c 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -32,8 +32,6 @@ #include <EGL/egl.h> #include <GLES/gl.h> -class SkBitmap; - namespace android { class Surface; @@ -150,6 +148,8 @@ private: // Display event handling class DisplayEventCallback; + std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver; + sp<Looper> mLooper; int displayEventCallback(int fd, int events, void* data); void processDisplayEvents(); @@ -202,8 +202,6 @@ private: sp<TimeCheckThread> mTimeCheckThread = nullptr; sp<Callbacks> mCallbacks; Animation* mAnimation = nullptr; - std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver; - sp<Looper> mLooper; }; // --------------------------------------------------------------------------- diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp index 1e200c52a207..437a87e8df54 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.cpp +++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp @@ -27,9 +27,9 @@ #include <cstring> #include <memory> -#include <android/log.h> #include <android/looper.h> #include <jni.h> +#include <log/log.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> @@ -37,10 +37,8 @@ #include <android-base/stringprintf.h> -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) -#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +// Log debug messages about the output. +static constexpr bool DEBUG_OUTPUT = false; namespace android { namespace uhid { @@ -61,7 +59,7 @@ static int handleLooperEvents(int /* fd */, int events, void* data) { static void checkAndClearException(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { - LOGE("An exception was thrown by callback '%s'.", methodName); + ALOGE("An exception was thrown by callback '%s'.", methodName); env->ExceptionClear(); } } @@ -115,9 +113,9 @@ void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) { checkAndClearException(env, "onDeviceGetReport"); } -void DeviceCallback::onDeviceOutput(const std::vector<uint8_t>& data) { +void DeviceCallback::onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data) { JNIEnv* env = getJNIEnv(); - env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, + env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType, toJbyteArray(env, data).get()); checkAndClearException(env, "onDeviceOutput"); } @@ -133,13 +131,13 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, std::unique_ptr<DeviceCallback> callback) { size_t size = descriptor.size(); if (size > HID_MAX_DESCRIPTOR_SIZE) { - LOGE("Received invalid hid report with descriptor size %zu, skipping", size); + ALOGE("Received invalid hid report with descriptor size %zu, skipping", size); return nullptr; } android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC)); if (!fd.ok()) { - LOGE("Failed to open uhid: %s", strerror(errno)); + ALOGE("Failed to open uhid: %s", strerror(errno)); return nullptr; } @@ -159,14 +157,14 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, errno = 0; ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { - LOGE("Failed to create uhid node: %s", strerror(errno)); + ALOGE("Failed to create uhid node: %s", strerror(errno)); return nullptr; } // Wait for the device to actually be created. ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); if (ret < 0 || ev.type != UHID_START) { - LOGE("uhid node failed to start: %s", strerror(errno)); + ALOGE("uhid node failed to start: %s", strerror(errno)); return nullptr; } // using 'new' to access non-public constructor @@ -177,7 +175,7 @@ Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCa : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) { ALooper* aLooper = ALooper_forThread(); if (aLooper == NULL) { - LOGE("Could not get ALooper, ALooper_forThread returned NULL"); + ALOGE("Could not get ALooper, ALooper_forThread returned NULL"); aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); } ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents, @@ -189,7 +187,7 @@ Device::~Device() { if (looper != NULL) { ALooper_removeFd(looper, mFd); } else { - LOGE("Could not remove fd, ALooper_forThread() returned NULL!"); + ALOGE("Could not remove fd, ALooper_forThread() returned NULL!"); } struct uhid_event ev = {}; ev.type = UHID_DESTROY; @@ -200,13 +198,13 @@ Device::~Device() { static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) { ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { - LOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); + ALOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); } } void Device::sendReport(const std::vector<uint8_t>& report) const { if (report.size() > UHID_DATA_MAX) { - LOGE("Received invalid report of size %zu, skipping", report.size()); + ALOGE("Received invalid report of size %zu, skipping", report.size()); return; } @@ -230,14 +228,14 @@ void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& int Device::handleEvents(int events) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { - LOGE("uhid node was closed or an error occurred. events=0x%x", events); + ALOGE("uhid node was closed or an error occurred. events=0x%x", events); mDeviceCallback->onDeviceError(); return 0; } struct uhid_event ev; ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); if (ret < 0) { - LOGE("Failed to read from uhid node: %s", strerror(errno)); + ALOGE("Failed to read from uhid node: %s", strerror(errno)); mDeviceCallback->onDeviceError(); return 0; } @@ -254,23 +252,28 @@ int Device::handleEvents(int events) { case UHID_SET_REPORT: { const struct uhid_set_report_req& set_report = ev.u.set_report; if (set_report.size > UHID_DATA_MAX) { - LOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); + ALOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); return 0; } std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size); - LOGI("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, - set_report.rnum, toString(data).c_str()); + if (DEBUG_OUTPUT) { + ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, + set_report.rnum, toString(data).c_str()); + } break; } case UHID_OUTPUT: { struct uhid_output_req& output = ev.u.output; std::vector<uint8_t> data(output.data, output.data + output.size); - mDeviceCallback->onDeviceOutput(data); + if (DEBUG_OUTPUT) { + ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str()); + } + mDeviceCallback->onDeviceOutput(output.rtype, data); break; } default: { - LOGI("Unhandled event type: %" PRIu32, ev.type); + ALOGI("Unhandled event type: %" PRIu32, ev.type); break; } } @@ -318,7 +321,7 @@ static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray ra if (d) { d->sendReport(report); } else { - LOGE("Could not send report, Device* is null!"); + ALOGE("Could not send report, Device* is null!"); } } @@ -329,7 +332,7 @@ static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr std::vector<uint8_t> report = getData(env, rawReport); d->sendGetFeatureReportReply(id, report); } else { - LOGE("Could not send get feature report reply, Device* is null!"); + ALOGE("Could not send get feature report reply, Device* is null!"); } } @@ -354,7 +357,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_commands_hid_Device(JNIEnv* env) { jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback"); if (clazz == NULL) { - LOGE("Unable to find class 'DeviceCallback'"); + ALOGE("Unable to find class 'DeviceCallback'"); return JNI_ERR; } uhid::gDeviceCallbackClassInfo.onDeviceOpen = @@ -362,12 +365,12 @@ int register_com_android_commands_hid_Device(JNIEnv* env) { uhid::gDeviceCallbackClassInfo.onDeviceGetReport = env->GetMethodID(clazz, "onDeviceGetReport", "(II)V"); uhid::gDeviceCallbackClassInfo.onDeviceOutput = - env->GetMethodID(clazz, "onDeviceOutput", "([B)V"); + env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V"); uhid::gDeviceCallbackClassInfo.onDeviceError = env->GetMethodID(clazz, "onDeviceError", "()V"); if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL || uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) { - LOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); + ALOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); return JNI_ERR; } diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h index 7202b45adcde..5483b40831a0 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.h +++ b/cmds/hid/jni/com_android_commands_hid_Device.h @@ -31,7 +31,7 @@ public: void onDeviceOpen(); void onDeviceGetReport(uint32_t requestId, uint8_t reportId); - void onDeviceOutput(const std::vector<uint8_t>& data); + void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data); void onDeviceError(); private: diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java index dade41511ae6..20b4bd86baec 100644 --- a/cmds/hid/src/com/android/commands/hid/Device.java +++ b/cmds/hid/src/com/android/commands/hid/Device.java @@ -26,6 +26,12 @@ import android.util.SparseArray; import com.android.internal.os.SomeArgs; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; @@ -38,12 +44,16 @@ public class Device { private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3; private static final int MSG_CLOSE_DEVICE = 4; + // Sync with linux uhid_event_type::UHID_OUTPUT + private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6; + private final int mId; private final HandlerThread mThread; private final DeviceHandler mHandler; // mFeatureReports is limited to 256 entries, because the report number is 8-bit private final SparseArray<byte[]> mFeatureReports; private final Map<ByteBuffer, byte[]> mOutputs; + private final OutputStream mOutputStream; private long mTimeToSend; private final Object mCond = new Object(); @@ -66,6 +76,7 @@ public class Device { mHandler = new DeviceHandler(mThread.getLooper()); mFeatureReports = featureReports; mOutputs = outputs; + mOutputStream = System.out; SomeArgs args = SomeArgs.obtain(); args.argi1 = id; args.argi2 = vid; @@ -188,7 +199,27 @@ public class Device { } // native callback - public void onDeviceOutput(byte[] data) { + public void onDeviceOutput(byte rtype, byte[] data) { + JSONObject json = new JSONObject(); + try { + json.put("eventId", UHID_EVENT_TYPE_UHID_OUTPUT); + json.put("deviceId", mId); + json.put("reportType", rtype); + JSONArray dataArray = new JSONArray(); + for (int i = 0; i < data.length; i++) { + dataArray.put(data[i] & 0xFF); + } + json.put("reportData", dataArray); + } catch (JSONException e) { + throw new RuntimeException("Could not create JSON object ", e); + } + try { + mOutputStream.write(json.toString().getBytes()); + mOutputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (mOutputs == null) { Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found"); return; diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 878cef94b674..e21a6b288fb3 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -181,7 +181,6 @@ cc_binary { "idmap2/Dump.cpp", "idmap2/Lookup.cpp", "idmap2/Main.cpp", - "idmap2/Scan.cpp", ], target: { android: { diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h index 69eea8d262d2..4099671066a2 100644 --- a/cmds/idmap2/idmap2/Commands.h +++ b/cmds/idmap2/idmap2/Commands.h @@ -26,6 +26,5 @@ android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::str android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<std::string>& args); android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args); android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args); -android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args); #endif // IDMAP2_IDMAP2_COMMANDS_H_ diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index 9682b6ead293..648b78e24c23 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -20,6 +20,7 @@ #include <fstream> #include <memory> #include <ostream> +#include <string> #include <vector> #include "androidfw/ResourceTypes.h" diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp index abdfaf4dccab..19622c4ef65a 100644 --- a/cmds/idmap2/idmap2/CreateMultiple.cpp +++ b/cmds/idmap2/idmap2/CreateMultiple.cpp @@ -20,6 +20,7 @@ #include <fstream> #include <memory> #include <ostream> +#include <string> #include <vector> #include "Commands.h" diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index fb093f0f22a4..aa6d0e76698f 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -53,8 +53,10 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) { int main(int argc, char** argv) { SYSTRACE << "main"; const NameToFunctionMap commands = { - {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup}, - {"scan", Scan}, + {"create", Create}, + {"create-multiple", CreateMultiple}, + {"dump", Dump}, + {"lookup", Lookup}, }; if (argc <= 1) { PrintUsage(commands, std::cerr); diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp deleted file mode 100644 index 36250450cc74..000000000000 --- a/cmds/idmap2/idmap2/Scan.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <dirent.h> - -#include <fstream> -#include <memory> -#include <ostream> -#include <set> -#include <string> -#include <utility> -#include <vector> - -#include "Commands.h" -#include "android-base/properties.h" -#include "idmap2/CommandLineOptions.h" -#include "idmap2/CommandUtils.h" -#include "idmap2/FileUtils.h" -#include "idmap2/Idmap.h" -#include "idmap2/Policies.h" -#include "idmap2/PolicyUtils.h" -#include "idmap2/ResourceUtils.h" -#include "idmap2/Result.h" -#include "idmap2/SysTrace.h" -#include "idmap2/XmlParser.h" - -using android::idmap2::CommandLineOptions; -using android::idmap2::Error; -using android::idmap2::Idmap; -using android::idmap2::Result; -using android::idmap2::Unit; -using android::idmap2::policy::kPolicyOdm; -using android::idmap2::policy::kPolicyOem; -using android::idmap2::policy::kPolicyProduct; -using android::idmap2::policy::kPolicyPublic; -using android::idmap2::policy::kPolicySystem; -using android::idmap2::policy::kPolicyVendor; -using android::idmap2::utils::ExtractOverlayManifestInfo; -using android::idmap2::utils::FindFiles; -using android::idmap2::utils::OverlayManifestInfo; -using android::idmap2::utils::PoliciesToBitmaskResult; - -using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; - -namespace { - -struct InputOverlay { - bool operator<(InputOverlay const& rhs) const { - return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path); - } - - std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes) - std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes) - int priority; // NOLINT(misc-non-private-member-variables-in-classes) - std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes) - bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes) -}; - -bool VendorIsQOrLater() { - constexpr int kQSdkVersion = 29; - constexpr int kBase = 10; - std::string version_prop = android::base::GetProperty("ro.vndk.version", "29"); - int version = strtol(version_prop.data(), nullptr, kBase); - - // If the string cannot be parsed, it is a development sdk codename. - return version >= kQSdkVersion || version == 0; -} - -Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs, - bool recursive) { - SYSTRACE << "FindApkFiles " << dirs << " " << recursive; - const auto predicate = [](unsigned char type, const std::string& path) -> bool { - static constexpr size_t kExtLen = 4; // strlen(".apk") - return type == DT_REG && path.size() > kExtLen && - path.compare(path.size() - kExtLen, kExtLen, ".apk") == 0; - }; - // pass apk paths through a set to filter out duplicates - std::set<std::string> paths; - for (const auto& dir : dirs) { - const auto apk_paths = FindFiles(dir, recursive, predicate); - if (!apk_paths) { - return Error("failed to open directory %s", dir.c_str()); - } - paths.insert(apk_paths->cbegin(), apk_paths->cend()); - } - return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend()); -} - -std::vector<std::string> PoliciesForPath(const std::string& apk_path) { - // clang-format off - static const std::vector<std::pair<std::string, std::string>> values = { - {"/odm/", kPolicyOdm}, - {"/oem/", kPolicyOem}, - {"/product/", kPolicyProduct}, - {"/system/", kPolicySystem}, - {"/system_ext/", kPolicySystem}, - {"/vendor/", kPolicyVendor}, - }; - // clang-format on - - std::vector<std::string> fulfilled_policies = {kPolicyPublic}; - for (auto const& pair : values) { - if (apk_path.compare(0, pair.first.size(), pair.first) == 0) { - fulfilled_policies.emplace_back(pair.second); - break; - } - } - - return fulfilled_policies; -} - -} // namespace - -Result<Unit> Scan(const std::vector<std::string>& args) { - SYSTRACE << "Scan " << args; - std::vector<std::string> input_directories; - std::string target_package_name; - std::string target_apk_path; - std::string output_directory; - std::vector<std::string> override_policies; - bool recursive = false; - - const CommandLineOptions opts = - CommandLineOptions("idmap2 scan") - .MandatoryOption("--input-directory", "directory containing overlay apks to scan", - &input_directories) - .OptionalFlag("--recursive", "also scan subfolders of overlay-directory", &recursive) - .MandatoryOption("--target-package-name", "package name of target package", - &target_package_name) - .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path) - .MandatoryOption("--output-directory", - "directory in which to write artifacts (idmap files and overlays.list)", - &output_directory) - .OptionalOption( - "--override-policy", - "input: an overlayable policy this overlay fulfills " - "(if none or supplied, the overlays will not have their policies overriden", - &override_policies); - const auto opts_ok = opts.Parse(args); - if (!opts_ok) { - return opts_ok.GetError(); - } - - const auto apk_paths = FindApkFiles(input_directories, recursive); - if (!apk_paths) { - return Error(apk_paths.GetError(), "failed to find apk files"); - } - - std::vector<InputOverlay> interesting_apks; - for (const std::string& path : **apk_paths) { - Result<OverlayManifestInfo> overlay_info = - ExtractOverlayManifestInfo(path, /* assert_overlay */ false); - if (!overlay_info) { - return overlay_info.GetError(); - } - - if (!overlay_info->is_static) { - continue; - } - - if (overlay_info->target_package.empty() || - overlay_info->target_package != target_package_name) { - continue; - } - - if (overlay_info->priority < 0) { - continue; - } - - // Note that conditional property enablement/exclusion only applies if - // the attribute is present. In its absence, all overlays are presumed enabled. - if (!overlay_info->requiredSystemPropertyName.empty() && - !overlay_info->requiredSystemPropertyValue.empty()) { - // if property set & equal to value, then include overlay - otherwise skip - if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") != - overlay_info->requiredSystemPropertyValue) { - continue; - } - } - - std::vector<std::string> fulfilled_policies; - if (!override_policies.empty()) { - fulfilled_policies = override_policies; - } else { - fulfilled_policies = PoliciesForPath(path); - } - - bool ignore_overlayable = false; - if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) != - fulfilled_policies.end() && - !VendorIsQOrLater()) { - // If the overlay is on a pre-Q vendor partition, do not enforce overlayable - // restrictions on this overlay because the pre-Q platform has no understanding of - // overlayable. - ignore_overlayable = true; - } - - std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path); - - // Sort the static overlays in ascending priority order - InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_policies, - ignore_overlayable}; - interesting_apks.insert( - std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input); - } - - std::stringstream stream; - for (const auto& overlay : interesting_apks) { - const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies); - if (!policy_bitmask) { - LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path - << "\": " << policy_bitmask.GetErrorMessage(); - continue; - } - - if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask, - !overlay.ignore_overlayable)) { - std::vector<std::string> create_args = {"--target-apk-path", target_apk_path, - "--overlay-apk-path", overlay.apk_path, - "--idmap-path", overlay.idmap_path}; - if (overlay.ignore_overlayable) { - create_args.emplace_back("--ignore-overlayable"); - } - - for (const std::string& policy : overlay.policies) { - create_args.emplace_back("--policy"); - create_args.emplace_back(policy); - } - - const auto create_ok = Create(create_args); - if (!create_ok) { - LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path - << "\": " << create_ok.GetError().GetMessage(); - continue; - } - } - - stream << overlay.idmap_path << std::endl; - } - - std::cout << stream.str(); - - return Unit{}; -} diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h index abee999dd2b2..1a445192aff8 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.h +++ b/cmds/idmap2/idmap2d/Idmap2Service.h @@ -17,6 +17,8 @@ #ifndef IDMAP2_IDMAP2D_IDMAP2SERVICE_H_ #define IDMAP2_IDMAP2D_IDMAP2SERVICE_H_ +#include <string> + #include <android-base/unique_fd.h> #include <binder/BinderService.h> diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index 02b27a8800b6..403d8c55de16 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -29,4 +29,5 @@ interface OverlayablePolicy { const int ODM_PARTITION = 0x00000020; const int OEM_PARTITION = 0x00000040; const int ACTOR_SIGNATURE = 0x00000080; + const int CONFIG_SIGNATURE = 0x0000100; } diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h index 3f03236d5e1a..c4e0e1fd8ef0 100644 --- a/cmds/idmap2/include/idmap2/FileUtils.h +++ b/cmds/idmap2/include/idmap2/FileUtils.h @@ -17,27 +17,13 @@ #ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_ #define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_ -#include <sys/types.h> - -#include <functional> -#include <memory> #include <string> -#include <vector> namespace android::idmap2::utils { constexpr const char* kIdmapCacheDir = "/data/resource-cache"; constexpr const mode_t kIdmapFilePermissionMask = 0133; // u=rw,g=r,o=r -typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)> - FindFilesPredicate; -std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, - const FindFilesPredicate& predicate); - -std::unique_ptr<std::string> ReadFile(int fd); - -std::unique_ptr<std::string> ReadFile(const std::string& path); - bool UidHasWriteAccessToPath(uid_t uid, const std::string& path); } // namespace android::idmap2::utils diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp index 3e8e32989a09..3af1f70ebe39 100644 --- a/cmds/idmap2/libidmap2/FileUtils.cpp +++ b/cmds/idmap2/libidmap2/FileUtils.cpp @@ -16,19 +16,7 @@ #include "idmap2/FileUtils.h" -#include <dirent.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cerrno> -#include <climits> -#include <cstdlib> -#include <cstring> -#include <fstream> -#include <memory> #include <string> -#include <utility> -#include <vector> #include "android-base/file.h" #include "android-base/macros.h" @@ -37,54 +25,6 @@ namespace android::idmap2::utils { -std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, - const FindFilesPredicate& predicate) { - DIR* dir = opendir(root.c_str()); - if (dir == nullptr) { - return nullptr; - } - std::unique_ptr<std::vector<std::string>> vector(new std::vector<std::string>()); - struct dirent* dirent; - while ((dirent = readdir(dir)) != nullptr) { - const std::string path = root + "/" + dirent->d_name; - if (predicate(dirent->d_type, path)) { - vector->push_back(path); - } - if (recurse && dirent->d_type == DT_DIR && strcmp(dirent->d_name, ".") != 0 && - strcmp(dirent->d_name, "..") != 0) { - auto sub_vector = FindFiles(path, recurse, predicate); - if (!sub_vector) { - closedir(dir); - return nullptr; - } - vector->insert(vector->end(), sub_vector->begin(), sub_vector->end()); - } - } - closedir(dir); - - return vector; -} - -std::unique_ptr<std::string> ReadFile(const std::string& path) { - std::unique_ptr<std::string> str(new std::string()); - std::ifstream fin(path); - str->append({std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>()}); - fin.close(); - return str; -} - -std::unique_ptr<std::string> ReadFile(int fd) { - static constexpr const size_t kBufSize = 1024; - - std::unique_ptr<std::string> str(new std::string()); - char buf[kBufSize]; - ssize_t r; - while ((r = read(fd, buf, sizeof(buf))) > 0) { - str->append(buf, r); - } - return r == 0 ? std::move(str) : nullptr; -} - #ifdef __ANDROID__ bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) { // resolve symlinks and relative paths; the directories must exist diff --git a/cmds/idmap2/libidmap2/PolicyUtils.cpp b/cmds/idmap2/libidmap2/PolicyUtils.cpp index fc5182af61c1..4e3f54d2583e 100644 --- a/cmds/idmap2/libidmap2/PolicyUtils.cpp +++ b/cmds/idmap2/libidmap2/PolicyUtils.cpp @@ -17,6 +17,8 @@ #include "include/idmap2/PolicyUtils.h" #include <sstream> +#include <string> +#include <vector> #include "android-base/strings.h" #include "idmap2/Policies.h" diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 34589a1c39dc..fd8b4eb86b4a 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -61,10 +61,13 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package, const ResourceId& target_resource) { static constexpr const PolicyBitmask sDefaultPolicies = PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | - PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE; + PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | + PolicyFlags::CONFIG_SIGNATURE; // If the resource does not have an overlayable definition, allow the resource to be overlaid if - // the overlay is preinstalled or signed with the same signature as the target. + // the overlay is preinstalled, signed with the same signature as the target or signed with the + // same signature as reference package defined in SystemConfig under 'overlay-config-signature' + // tag. if (!target_package.DefinesOverlayable()) { return (sDefaultPolicies & fulfilled_policies) != 0 ? Result<Unit>({}) diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 5bd353af4ad3..cdce45191094 100644 --- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ -#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ +#ifndef IDMAP2_LIBIDMAP2_POLICIES_INCLUDE_IDMAP2_POLICIES_H_ +#define IDMAP2_LIBIDMAP2_POLICIES_INCLUDE_IDMAP2_POLICIES_H_ #include <array> #include <string> +#include <utility> #include <vector> #include "android-base/stringprintf.h" @@ -37,16 +38,18 @@ constexpr const char* kPolicyOdm = "odm"; constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyProduct = "product"; constexpr const char* kPolicyPublic = "public"; +constexpr const char* kPolicyConfigSignature = "config_signature"; constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicyVendor = "vendor"; -inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = { +inline static const std::array<std::pair<StringPiece, PolicyFlags>, 9> kPolicyStringToFlag = { std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE}, {kPolicyOdm, PolicyFlags::ODM_PARTITION}, {kPolicyOem, PolicyFlags::OEM_PARTITION}, {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, {kPolicyPublic, PolicyFlags::PUBLIC}, + {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE}, {kPolicySignature, PolicyFlags::SIGNATURE}, {kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, {kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, @@ -76,4 +79,4 @@ inline static std::string PoliciesToDebugString(PolicyBitmask policies) { } // namespace android::idmap2::policy -#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ +#endif // IDMAP2_LIBIDMAP2_POLICIES_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index 8af4037be954..5750ca1f49c5 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -14,73 +14,16 @@ * limitations under the License. */ -#include <dirent.h> -#include <fcntl.h> - -#include <set> #include <string> #include "TestHelpers.h" -#include "android-base/macros.h" #include "android-base/stringprintf.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "idmap2/FileUtils.h" #include "private/android_filesystem_config.h" -using ::testing::NotNull; - namespace android::idmap2::utils { -TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) { - const auto& root = GetTestDataPath(); - auto v = utils::FindFiles(root, false, - [](unsigned char type ATTRIBUTE_UNUSED, - const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; }); - ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 7U); - ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({ - root + "/.", - root + "/..", - root + "/overlay", - root + "/target", - root + "/signature-overlay", - root + "/system-overlay", - root + "/system-overlay-invalid", - })); -} - -TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) { - const auto& root = GetTestDataPath(); - auto v = utils::FindFiles(root, true, [](unsigned char type, const std::string& path) -> bool { - return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0; - }); - ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 11U); - ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), - std::set<std::string>( - {root + "/target/target.apk", root + "/target/target-no-overlayable.apk", - root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk", - root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-shared.apk", - root + "/overlay/overlay-static-1.apk", root + "/overlay/overlay-static-2.apk", - root + "/signature-overlay/signature-overlay.apk", - root + "/system-overlay/system-overlay.apk", - root + "/system-overlay-invalid/system-overlay-invalid.apk"})); -} - -TEST(FileUtilsTests, ReadFile) { - int pipefd[2]; - ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0); - - ASSERT_EQ(write(pipefd[1], "foobar", 6), 6); - close(pipefd[1]); - - auto data = ReadFile(pipefd[0]); - ASSERT_THAT(data, NotNull()); - ASSERT_EQ(*data, "foobar"); - close(pipefd[0]); -} - #ifdef __ANDROID__ TEST(FileUtilsTests, UidHasWriteAccessToPath) { constexpr const char* tmp_path = "/data/local/tmp/test@idmap"; diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index d896cf9c11ba..61751b33dcba 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -159,131 +159,6 @@ TEST_F(Idmap2BinaryTests, Dump) { unlink(GetIdmapPath().c_str()); } -TEST_F(Idmap2BinaryTests, Scan) { - SKIP_TEST_IF_CANT_EXEC_IDMAP2; - - const std::string overlay_static_no_name_apk_path = - GetTestDataPath() + "/overlay/overlay-no-name-static.apk"; - const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk"; - const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk"; - const std::string idmap_static_no_name_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_no_name_apk_path); - const std::string idmap_static_1_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_1_apk_path); - const std::string idmap_static_2_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_2_apk_path); - - // single input directory, recursive - // clang-format off - auto result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - std::stringstream expected; - expected << idmap_static_no_name_path << std::endl; - expected << idmap_static_1_path << std::endl; - expected << idmap_static_2_path << std::endl; - ASSERT_EQ(result->stdout, expected.str()); - - auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path); - auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string); - auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream); - ASSERT_TRUE(idmap_static_no_name); - ASSERT_IDMAP(**idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path); - - auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path); - auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string); - auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream); - ASSERT_TRUE(idmap_static_1); - ASSERT_IDMAP(**idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path); - - auto idmap_static_2_raw_string = utils::ReadFile(idmap_static_2_path); - auto idmap_static_2_raw_stream = std::istringstream(*idmap_static_2_raw_string); - auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream); - ASSERT_TRUE(idmap_static_2); - ASSERT_IDMAP(**idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path); - - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // multiple input directories, non-recursive - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath() + "/target", - "--input-directory", GetTestDataPath() + "/overlay", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // the same input directory given twice, but no duplicate entries - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // no APKs in input-directory: ok, but no output - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTempDirPath(), - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, ""); - - // the signature idmap failing to generate should not cause scanning to fail - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); -} - TEST_F(Idmap2BinaryTests, Lookup) { SKIP_TEST_IF_CANT_EXEC_IDMAP2; diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h index aed263a49aa3..854b57fb22aa 100644 --- a/cmds/idmap2/tests/R.h +++ b/cmds/idmap2/tests/R.h @@ -14,10 +14,12 @@ * limitations under the License. */ -#ifndef IDMAP2_TESTS_R_H -#define IDMAP2_TESTS_R_H +#ifndef IDMAP2_TESTS_R_H_ +#define IDMAP2_TESTS_R_H_ -#include <idmap2/ResourceUtils.h> +#include <string> + +#include "idmap2/ResourceUtils.h" namespace android::idmap2 { @@ -29,42 +31,43 @@ static std::string hexify(ResourceId id) { // clang-format off namespace R::target { - namespace integer { + namespace integer { // NOLINT(runtime/indentation_namespace) constexpr ResourceId int1 = 0x7f010000; - namespace literal { + namespace literal { // NOLINT(runtime/indentation_namespace) inline const std::string int1 = hexify(R::target::integer::int1); } } - namespace string { + namespace string { // NOLINT(runtime/indentation_namespace) constexpr ResourceId not_overlayable = 0x7f020003; constexpr ResourceId other = 0x7f020004; constexpr ResourceId policy_actor = 0x7f020005; - constexpr ResourceId policy_odm = 0x7f020006; - constexpr ResourceId policy_oem = 0x7f020007; - constexpr ResourceId policy_product = 0x7f020008; - constexpr ResourceId policy_public = 0x7f020009; - constexpr ResourceId policy_signature = 0x7f02000a; - constexpr ResourceId policy_system = 0x7f02000b; - constexpr ResourceId policy_system_vendor = 0x7f02000c; - constexpr ResourceId str1 = 0x7f02000d; - constexpr ResourceId str3 = 0x7f02000f; - constexpr ResourceId str4 = 0x7f020010; + constexpr ResourceId policy_config_signature = 0x7f020006; + constexpr ResourceId policy_odm = 0x7f020007; + constexpr ResourceId policy_oem = 0x7f020008; + constexpr ResourceId policy_product = 0x7f020009; + constexpr ResourceId policy_public = 0x7f02000a; + constexpr ResourceId policy_signature = 0x7f02000b; + constexpr ResourceId policy_system = 0x7f02000c; + constexpr ResourceId policy_system_vendor = 0x7f02000d; + constexpr ResourceId str1 = 0x7f02000e; + constexpr ResourceId str3 = 0x7f020010; + constexpr ResourceId str4 = 0x7f020011; - namespace literal { + namespace literal { // NOLINT(runtime/indentation_namespace) inline const std::string str1 = hexify(R::target::string::str1); inline const std::string str3 = hexify(R::target::string::str3); inline const std::string str4 = hexify(R::target::string::str4); } - } -} + } // namespace string +} // namespace R::target namespace R::overlay { - namespace integer { + namespace integer { // NOLINT(runtime/indentation_namespace) constexpr ResourceId int1 = 0x7f010000; } - namespace string { + namespace string { // NOLINT(runtime/indentation_namespace) constexpr ResourceId str1 = 0x7f020000; constexpr ResourceId str3 = 0x7f020001; constexpr ResourceId str4 = 0x7f020002; @@ -72,10 +75,10 @@ namespace R::overlay { } namespace R::overlay_shared { - namespace integer { + namespace integer { // NOLINT(runtime/indentation_namespace) constexpr ResourceId int1 = 0x00010000; } - namespace string { + namespace string { // NOLINT(runtime/indentation_namespace) constexpr ResourceId str1 = 0x00020000; constexpr ResourceId str3 = 0x00020001; constexpr ResourceId str4 = 0x00020002; @@ -92,16 +95,17 @@ namespace R::system_overlay_invalid::string { constexpr ResourceId not_overlayable = 0x7f010000; constexpr ResourceId other = 0x7f010001; constexpr ResourceId policy_actor = 0x7f010002; - constexpr ResourceId policy_odm = 0x7f010003; - constexpr ResourceId policy_oem = 0x7f010004; - constexpr ResourceId policy_product = 0x7f010005; - constexpr ResourceId policy_public = 0x7f010006; - constexpr ResourceId policy_signature = 0x7f010007; - constexpr ResourceId policy_system = 0x7f010008; - constexpr ResourceId policy_system_vendor = 0x7f010009; -}; + constexpr ResourceId policy_config_signature = 0x7f010003; + constexpr ResourceId policy_odm = 0x7f010004; + constexpr ResourceId policy_oem = 0x7f010005; + constexpr ResourceId policy_product = 0x7f010006; + constexpr ResourceId policy_public = 0x7f010007; + constexpr ResourceId policy_signature = 0x7f010008; + constexpr ResourceId policy_system = 0x7f010009; + constexpr ResourceId policy_system_vendor = 0x7f01000a; +} // namespace R::system_overlay_invalid::string // clang-format on } // namespace android::idmap2 -#endif // IDMAP2_TESTS_R_H +#endif // IDMAP2_TESTS_R_H_ diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index de039f440e33..3ec6ac24b238 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -237,7 +237,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -256,6 +256,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -298,8 +302,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) { ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); } -// Overlays that are pre-installed or are signed with the same signature as the target can overlay -// packages that have not defined overlayable resources. +// Overlays that are pre-installed or are signed with the same signature as the target or are signed +// with the same signature as the reference package can overlay packages that have not defined +// overlayable resources. TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void { auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", @@ -309,7 +314,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -330,6 +335,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -342,6 +351,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { }; CheckEntries(PolicyFlags::SIGNATURE); + CheckEntries(PolicyFlags::CONFIG_SIGNATURE); CheckEntries(PolicyFlags::PRODUCT_PARTITION); CheckEntries(PolicyFlags::SYSTEM_PARTITION); CheckEntries(PolicyFlags::VENDOR_PARTITION); diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h index 6bc924e5ac3c..9641f6b55670 100644 --- a/cmds/idmap2/tests/TestConstants.h +++ b/cmds/idmap2/tests/TestConstants.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#ifndef IDMAP2_TESTS_TESTCONSTANTS_H -#define IDMAP2_TESTS_TESTCONSTANTS_H +#ifndef IDMAP2_TESTS_TESTCONSTANTS_H_ +#define IDMAP2_TESTS_TESTCONSTANTS_H_ namespace android::idmap2::TestConstants { -constexpr const auto TARGET_CRC = 0x41c60c8c; -constexpr const auto TARGET_CRC_STRING = "41c60c8c"; +constexpr const auto TARGET_CRC = 0x7c2d4719; +constexpr const auto TARGET_CRC_STRING = "7c2d4719"; -constexpr const auto OVERLAY_CRC = 0xc054fb26; -constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; +constexpr const auto OVERLAY_CRC = 0x5afff726; +constexpr const auto OVERLAY_CRC_STRING = "5afff726"; } // namespace android::idmap2::TestConstants -#endif // IDMAP2_TESTS_TESTCONSTANTS_H +#endif // IDMAP2_TESTS_TESTCONSTANTS_H_ diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk Binary files differindex 7c25985e5a61..dab25b1f8131 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk Binary files differindex c75f3e1dbddf..c8b95c2601ad 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk Binary files differindex 93dcc82f9358..0a8b7372172e 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk Binary files differindex 5b8a6e4a90ed..fd41182f8493 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk Binary files differindex 698a1fd6e702..b24765fc666a 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk Binary files differindex 1db303ff05b5..870575efa10c 100644 --- a/cmds/idmap2/tests/data/overlay/overlay.apk +++ b/cmds/idmap2/tests/data/overlay/overlay.apk diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk Binary files differindex 51e19de082ed..e0fd20499671 100644 --- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk +++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml index 7119d8283061..ebaf49c34762 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml +++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml @@ -26,6 +26,7 @@ <string name="policy_odm">policy_odm</string> <string name="policy_oem">policy_oem</string> <string name="policy_actor">policy_actor</string> + <string name="policy_config_signature">policy_config_signature</string> <!-- Requests to overlay a resource that is not declared as overlayable. --> <string name="not_overlayable">not_overlayable</string> diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk Binary files differindex bd990983693c..a63daf86caf5 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk +++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk Binary files differindex a0fba4378b57..90d2803a1eca 100644 --- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk +++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml index ad4cd4882632..57e6c439c23c 100644 --- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml +++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml @@ -45,6 +45,10 @@ <item type="string" name="policy_actor" /> </policy> + <policy type="config_signature"> + <item type="string" name="policy_config_signature"/> + </policy> + <!-- Resources publicly overlayable --> <policy type="public"> <item type="string" name="policy_public" /> diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index 5230e25e626b..00909a9e481c 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -37,6 +37,7 @@ <string name="policy_system">policy_system</string> <string name="policy_system_vendor">policy_system_vendor</string> <string name="policy_actor">policy_actor</string> + <string name="policy_config_signature">policy_config_signature</string> <string name="other">other</string> </resources> diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk Binary files differindex 58504a74a83a..cc3491de894d 100644 --- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk +++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk Binary files differindex c80e5eb65ff2..4a58c5e28f49 100644 --- a/cmds/idmap2/tests/data/target/target.apk +++ b/cmds/idmap2/tests/data/target/target.apk diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh index b4ebab0c7ffe..84daeecdb21e 100755 --- a/cmds/idmap2/valgrind.sh +++ b/cmds/idmap2/valgrind.sh @@ -53,7 +53,5 @@ valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full" _eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path" _eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path" _eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1" -_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public" -_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path" _eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests" exit $errors diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index dc1612575f38..13bf197aa9dc 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -554,6 +554,10 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8 return NO_ERROR; } if (!args[0].compare(String8("section"))) { + if (argCount == 1) { + fprintf(out, "Not enough arguments for section\n"); + return NO_ERROR; + } int id = atoi(args[1]); int idx = 0; while (SECTION_LIST[idx] != NULL) { diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp index 3a45af028518..60f7fb788837 100644 --- a/cmds/incidentd/tests/section_list.cpp +++ b/cmds/incidentd/tests/section_list.cpp @@ -1,4 +1,4 @@ -// This file is a dummy section_list.cpp used for test only. +// This file is a stub section_list.cpp used for test only. #include "section_list.h" #include "frameworks/base/cmds/incidentd/tests/test_proto.pb.h" diff --git a/cmds/input/Android.bp b/cmds/input/Android.bp index a0ebde63eb6e..1ee9dd355290 100644 --- a/cmds/input/Android.bp +++ b/cmds/input/Android.bp @@ -1,8 +1,7 @@ // Copyright 2008 The Android Open Source Project // -java_binary { +sh_binary { name: "input", - wrapper: "input", - srcs: ["**/*.java"], + src: "input", } diff --git a/cmds/input/input b/cmds/input/input index 2625eba17153..d7d041431b49 100755 --- a/cmds/input/input +++ b/cmds/input/input @@ -1,3 +1,2 @@ #!/system/bin/sh -export CLASSPATH=/system/framework/input.jar -exec app_process /system/bin com.android.commands.input.Input "$@" +cmd input "$@" diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java deleted file mode 100644 index 08216d9b3f1d..000000000000 --- a/cmds/input/src/com/android/commands/input/Input.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (C) 2007 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.commands.input; - -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; - -import android.hardware.input.InputManager; -import android.os.SystemClock; -import android.view.InputDevice; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -import com.android.internal.os.BaseCommand; - -import java.io.PrintStream; -import java.util.HashMap; -import java.util.Map; - -/** - * Command that sends key events to the device, either by their keycode, or by - * desired character output. - */ - -public class Input extends BaseCommand { - private static final String TAG = "Input"; - private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: "; - private static final String INVALID_DISPLAY_ARGUMENTS = - "Error: Invalid arguments for display ID."; - - private static final float DEFAULT_PRESSURE = 1.0f; - private static final float NO_PRESSURE = 0.0f; - - private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{ - put("keyboard", InputDevice.SOURCE_KEYBOARD); - put("dpad", InputDevice.SOURCE_DPAD); - put("gamepad", InputDevice.SOURCE_GAMEPAD); - put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); - put("mouse", InputDevice.SOURCE_MOUSE); - put("stylus", InputDevice.SOURCE_STYLUS); - put("trackball", InputDevice.SOURCE_TRACKBALL); - put("touchpad", InputDevice.SOURCE_TOUCHPAD); - put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); - put("joystick", InputDevice.SOURCE_JOYSTICK); - }}; - - private static final Map<String, InputCmd> COMMANDS = new HashMap<String, InputCmd>(); - - /** - * Command-line entry point. - * - * @param args The command-line arguments - */ - public static void main(String[] args) { - (new Input()).run(args); - } - - Input() { - COMMANDS.put("text", new InputText()); - COMMANDS.put("keyevent", new InputKeyEvent()); - COMMANDS.put("tap", new InputTap()); - COMMANDS.put("swipe", new InputSwipe()); - COMMANDS.put("draganddrop", new InputDragAndDrop()); - COMMANDS.put("press", new InputPress()); - COMMANDS.put("roll", new InputRoll()); - COMMANDS.put("motionevent", new InputMotionEvent()); - } - - @Override - public void onRun() throws Exception { - String arg = nextArgRequired(); - int inputSource = InputDevice.SOURCE_UNKNOWN; - - // Get source (optional). - if (SOURCES.containsKey(arg)) { - inputSource = SOURCES.get(arg); - arg = nextArgRequired(); - } - - // Get displayId (optional). - int displayId = INVALID_DISPLAY; - if ("-d".equals(arg)) { - displayId = getDisplayId(); - arg = nextArgRequired(); - } - - // Get command and run. - InputCmd cmd = COMMANDS.get(arg); - if (cmd != null) { - try { - cmd.run(inputSource, displayId); - return; - } catch (NumberFormatException ex) { - throw new IllegalArgumentException(INVALID_ARGUMENTS + arg); - } - } - - throw new IllegalArgumentException("Error: Unknown command: " + arg); - } - - private int getDisplayId() { - String displayArg = nextArgRequired(); - if ("INVALID_DISPLAY".equalsIgnoreCase(displayArg)) { - return INVALID_DISPLAY; - } else if ("DEFAULT_DISPLAY".equalsIgnoreCase(displayArg)) { - return DEFAULT_DISPLAY; - } else { - try { - final int displayId = Integer.parseInt(displayArg); - if (displayId == INVALID_DISPLAY) { - return INVALID_DISPLAY; - } - return Math.max(displayId, 0); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(INVALID_DISPLAY_ARGUMENTS); - } - } - } - - class InputText implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); - sendText(inputSource, nextArgRequired(), displayId); - } - - /** - * Convert the characters of string text into key event's and send to - * device. - * - * @param text is a string of characters you want to input to the device. - */ - private void sendText(int source, final String text, int displayId) { - final StringBuffer buff = new StringBuffer(text); - boolean escapeFlag = false; - for (int i = 0; i < buff.length(); i++) { - if (escapeFlag) { - escapeFlag = false; - if (buff.charAt(i) == 's') { - buff.setCharAt(i, ' '); - buff.deleteCharAt(--i); - } - } - if (buff.charAt(i) == '%') { - escapeFlag = true; - } - } - - final char[] chars = buff.toString().toCharArray(); - final KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - final KeyEvent[] events = kcm.getEvents(chars); - for (int i = 0; i < events.length; i++) { - KeyEvent e = events[i]; - if (source != e.getSource()) { - e.setSource(source); - } - e.setDisplayId(displayId); - injectKeyEvent(e); - } - } - } - - class InputKeyEvent implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - String arg = nextArgRequired(); - final boolean longpress = "--longpress".equals(arg); - if (longpress) { - arg = nextArgRequired(); - } - - do { - final int keycode = KeyEvent.keyCodeFromString(arg); - sendKeyEvent(inputSource, keycode, longpress, displayId); - } while ((arg = nextArg()) != null); - } - - private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) { - final long now = SystemClock.uptimeMillis(); - int repeatCount = 0; - - KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount, - 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, - inputSource); - event.setDisplayId(displayId); - - injectKeyEvent(event); - if (longpress) { - repeatCount++; - injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount, - KeyEvent.FLAG_LONG_PRESS)); - } - injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); - } - } - - class InputTap implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - sendTap(inputSource, Float.parseFloat(nextArgRequired()), - Float.parseFloat(nextArgRequired()), displayId); - } - - void sendTap(int inputSource, float x, float y, int displayId) { - final long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, now, x, y, 1.0f, - displayId); - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, now, x, y, 0.0f, displayId); - } - } - - class InputPress extends InputTap { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); - sendTap(inputSource, 0.0f, 0.0f, displayId); - } - } - - class InputSwipe implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - sendSwipe(inputSource, displayId, false); - } - - void sendSwipe(int inputSource, int displayId, boolean isDragDrop) { - // Parse two points and duration. - final float x1 = Float.parseFloat(nextArgRequired()); - final float y1 = Float.parseFloat(nextArgRequired()); - final float x2 = Float.parseFloat(nextArgRequired()); - final float y2 = Float.parseFloat(nextArgRequired()); - String durationArg = nextArg(); - int duration = durationArg != null ? Integer.parseInt(durationArg) : -1; - if (duration < 0) { - duration = 300; - } - - final long down = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, down, down, x1, y1, 1.0f, - displayId); - if (isDragDrop) { - // long press until drag start. - try { - Thread.sleep(ViewConfiguration.getLongPressTimeout()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - long now = SystemClock.uptimeMillis(); - final long endTime = down + duration; - while (now < endTime) { - final long elapsedTime = now - down; - final float alpha = (float) elapsedTime / duration; - injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, down, now, - lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f, displayId); - now = SystemClock.uptimeMillis(); - } - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, down, now, x2, y2, 0.0f, - displayId); - } - } - - class InputDragAndDrop extends InputSwipe { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - sendSwipe(inputSource, displayId, true); - } - } - - class InputRoll implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); - sendMove(inputSource, Float.parseFloat(nextArgRequired()), - Float.parseFloat(nextArgRequired()), displayId); - } - - /** - * Sends a simple zero-pressure move event. - * - * @param inputSource the InputDevice.SOURCE_* sending the input event - * @param dx change in x coordinate due to move - * @param dy change in y coordinate due to move - */ - private void sendMove(int inputSource, float dx, float dy, int displayId) { - final long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, now, dx, dy, 0.0f, - displayId); - } - } - - class InputMotionEvent implements InputCmd { - @Override - public void run(int inputSource, int displayId) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - sendMotionEvent(inputSource, nextArgRequired(), Float.parseFloat(nextArgRequired()), - Float.parseFloat(nextArgRequired()), displayId); - } - - private void sendMotionEvent(int inputSource, String motionEventType, float x, float y, - int displayId) { - final int action; - final float pressure; - - switch (motionEventType.toUpperCase()) { - case "DOWN": - action = MotionEvent.ACTION_DOWN; - pressure = DEFAULT_PRESSURE; - break; - case "UP": - action = MotionEvent.ACTION_UP; - pressure = NO_PRESSURE; - break; - case "MOVE": - action = MotionEvent.ACTION_MOVE; - pressure = DEFAULT_PRESSURE; - break; - default: - throw new IllegalArgumentException("Unknown motionevent " + motionEventType); - } - - final long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, action, now, now, x, y, pressure, displayId); - } - } - - /** - * Abstract class for command - * use nextArgRequired or nextArg to check next argument if necessary. - */ - private interface InputCmd { - void run(int inputSource, int displayId); - } - - private static void injectKeyEvent(KeyEvent event) { - InputManager.getInstance().injectInputEvent(event, - InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); - } - - private static int getInputDeviceId(int inputSource) { - final int DEFAULT_DEVICE_ID = 0; - int[] devIds = InputDevice.getDeviceIds(); - for (int devId : devIds) { - InputDevice inputDev = InputDevice.getDevice(devId); - if (inputDev.supportsSource(inputSource)) { - return devId; - } - } - return DEFAULT_DEVICE_ID; - } - - /** - * Builds a MotionEvent and injects it into the event stream. - * - * @param inputSource the InputDevice.SOURCE_* sending the input event - * @param action the MotionEvent.ACTION_* for the event - * @param downTime the value of the ACTION_DOWN event happened - * @param when the value of SystemClock.uptimeMillis() at which the event happened - * @param x x coordinate of event - * @param y y coordinate of event - * @param pressure pressure of event - */ - private static void injectMotionEvent(int inputSource, int action, long downTime, long when, - float x, float y, float pressure, int displayId) { - final float DEFAULT_SIZE = 1.0f; - final int DEFAULT_META_STATE = 0; - final float DEFAULT_PRECISION_X = 1.0f; - final float DEFAULT_PRECISION_Y = 1.0f; - final int DEFAULT_EDGE_FLAGS = 0; - MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure, DEFAULT_SIZE, - DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, - getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS); - event.setSource(inputSource); - if (displayId == INVALID_DISPLAY && (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) { - displayId = DEFAULT_DISPLAY; - } - event.setDisplayId(displayId); - InputManager.getInstance().injectInputEvent(event, - InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); - } - - private static final float lerp(float a, float b, float alpha) { - return (b - a) * alpha + a; - } - - private static final int getSource(int inputSource, int defaultSource) { - return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource; - } - - @Override - public void onShowUsage(PrintStream out) { - out.println("Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...]"); - out.println(); - out.println("The sources are: "); - for (String src : SOURCES.keySet()) { - out.println(" " + src); - } - out.println(); - out.printf("-d: specify the display ID.\n" - + " (Default: %d for key event, %d for motion event if not specified.)", - INVALID_DISPLAY, DEFAULT_DISPLAY); - out.println(); - out.println("The commands and default sources are:"); - out.println(" text <string> (Default: touchscreen)"); - out.println(" keyevent [--longpress] <key code number or name> ..." - + " (Default: keyboard)"); - out.println(" tap <x> <y> (Default: touchscreen)"); - out.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]" - + " (Default: touchscreen)"); - out.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]" - + " (Default: touchscreen)"); - out.println(" press (Default: trackball)"); - out.println(" roll <dx> <dy> (Default: trackball)"); - out.println(" motionevent <DOWN|UP|MOVE> <x> <y> (Default: touchscreen)"); - } -} diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING index 56f5cc034f05..c1cba5f7f22d 100644 --- a/cmds/locksettings/TEST_MAPPING +++ b/cmds/locksettings/TEST_MAPPING @@ -1,5 +1,5 @@ { - "presubmit-devicepolicy": [ + "presubmit": [ { "name": "CtsDevicePolicyManagerTestCases", "options": [ diff --git a/cmds/screencap/Android.bp b/cmds/screencap/Android.bp index 248c67589696..fc628a696afa 100644 --- a/cmds/screencap/Android.bp +++ b/cmds/screencap/Android.bp @@ -7,7 +7,7 @@ cc_binary { "libcutils", "libutils", "libbinder", - "libhwui", + "libjnigraphics", "libui", "libgui", ], diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index bb32dd2fa7ad..5c08704a6623 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -26,10 +26,13 @@ #include <sys/mman.h> #include <sys/wait.h> +#include <android/bitmap.h> + #include <binder/ProcessState.h> -#include <gui/SurfaceComposerClient.h> #include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SyncScreenCaptureListener.h> #include <ui/DisplayInfo.h> #include <ui/GraphicTypes.h> @@ -37,14 +40,6 @@ #include <system/graphics.h> -// TODO: Fix Skia. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <SkImageEncoder.h> -#include <SkData.h> -#include <SkColorSpace.h> -#pragma GCC diagnostic pop - using namespace android; #define COLORSPACE_UNKNOWN 0 @@ -57,33 +52,20 @@ static void usage(const char* pname, PhysicalDisplayId displayId) "usage: %s [-hp] [-d display-id] [FILENAME]\n" " -h: this message\n" " -p: save the file as a png.\n" - " -d: specify the physical display ID to capture (default: %" - ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n" + " -d: specify the physical display ID to capture (default: %s)\n" " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", - pname, displayId); + pname, to_string(displayId).c_str()); } -static SkColorType flinger2skia(PixelFormat f) +static int32_t flinger2bitmapFormat(PixelFormat f) { switch (f) { case PIXEL_FORMAT_RGB_565: - return kRGB_565_SkColorType; - default: - return kN32_SkColorType; - } -} - -static sk_sp<SkColorSpace> dataSpaceToColorSpace(ui::Dataspace d) -{ - switch (d) { - case ui::Dataspace::V0_SRGB: - return SkColorSpace::MakeSRGB(); - case ui::Dataspace::DISPLAY_P3: - return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); + return ANDROID_BITMAP_FORMAT_RGB_565; default: - return nullptr; + return ANDROID_BITMAP_FORMAT_RGBA_8888; } } @@ -155,7 +137,7 @@ int main(int argc, char** argv) png = true; break; case 'd': - displayId = atoll(optarg); + displayId = PhysicalDisplayId(atoll(optarg)); break; case '?': case 'h': @@ -192,8 +174,6 @@ int main(int argc, char** argv) ssize_t mapsize = -1; void* base = NULL; - uint32_t w, s, h, f; - size_t size = 0; // setThreadPoolMaxThreadCount(0) actually tells the kernel it's // not allowed to spawn any additional threads, but we still spawn @@ -202,16 +182,22 @@ int main(int argc, char** argv) ProcessState::self()->setThreadPoolMaxThreadCount(0); ProcessState::self()->startThreadPool(); - ui::Dataspace outDataspace; - sp<GraphicBuffer> outBuffer; - - status_t result = ScreenshotClient::capture(*displayId, &outDataspace, &outBuffer); + sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); + status_t result = ScreenshotClient::captureDisplay(displayId->value, captureListener); if (result != NO_ERROR) { close(fd); return 1; } - result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base); + ScreenCaptureResults captureResults = captureListener->waitForResults(); + if (captureResults.result != NO_ERROR) { + close(fd); + return 1; + } + ui::Dataspace dataspace = captureResults.capturedDataspace; + sp<GraphicBuffer> buffer = captureResults.buffer; + + result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base); if (base == nullptr || result != NO_ERROR) { String8 reason; @@ -225,33 +211,36 @@ int main(int argc, char** argv) return 1; } - w = outBuffer->getWidth(); - h = outBuffer->getHeight(); - s = outBuffer->getStride(); - f = outBuffer->getPixelFormat(); - size = s * h * bytesPerPixel(f); - if (png) { - const SkImageInfo info = - SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, - dataSpaceToColorSpace(outDataspace)); - SkPixmap pixmap(info, base, s * bytesPerPixel(f)); - struct FDWStream final : public SkWStream { - size_t fBytesWritten = 0; - int fFd; - FDWStream(int f) : fFd(f) {} - size_t bytesWritten() const override { return fBytesWritten; } - bool write(const void* buffer, size_t size) override { - fBytesWritten += size; - return size == 0 || ::write(fFd, buffer, size) > 0; - } - } fdStream(fd); - (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); + AndroidBitmapInfo info; + info.format = flinger2bitmapFormat(buffer->getPixelFormat()); + info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; + info.width = buffer->getWidth(); + info.height = buffer->getHeight(); + info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); + + int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base, + ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd, + [](void* fdPtr, const void* data, size_t size) -> bool { + int bytesWritten = write(*static_cast<int*>(fdPtr), + data, size); + return bytesWritten == size; + }); + + if (result != ANDROID_BITMAP_RESULT_SUCCESS) { + fprintf(stderr, "Failed to compress PNG (error code: %d)\n", result); + } + if (fn != NULL) { notifyMediaScanner(fn); } } else { - uint32_t c = dataSpaceToInt(outDataspace); + uint32_t w = buffer->getWidth(); + uint32_t h = buffer->getHeight(); + uint32_t s = buffer->getStride(); + uint32_t f = buffer->getPixelFormat(); + uint32_t c = dataSpaceToInt(dataspace); + write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 0617eb6c0e66..88db1d84df8e 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -73,10 +73,10 @@ cc_defaults { "src/HashableDimensionKey.cpp", "src/logd/LogEvent.cpp", "src/logd/LogEventQueue.cpp", - "src/matchers/CombinationLogMatchingTracker.cpp", + "src/matchers/CombinationAtomMatchingTracker.cpp", "src/matchers/EventMatcherWizard.cpp", "src/matchers/matcher_util.cpp", - "src/matchers/SimpleLogMatchingTracker.cpp", + "src/matchers/SimpleAtomMatchingTracker.cpp", "src/metadata_util.cpp", "src/metrics/CountMetricProducer.cpp", "src/metrics/duration_helper/MaxDurationTracker.cpp", @@ -85,8 +85,9 @@ cc_defaults { "src/metrics/EventMetricProducer.cpp", "src/metrics/GaugeMetricProducer.cpp", "src/metrics/MetricProducer.cpp", - "src/metrics/metrics_manager_util.cpp", "src/metrics/MetricsManager.cpp", + "src/metrics/parsing_utils/config_update_utils.cpp", + "src/metrics/parsing_utils/metrics_manager_util.cpp", "src/metrics/ValueMetricProducer.cpp", "src/packages/UidMap.cpp", "src/shell/shell_config.proto", @@ -171,7 +172,8 @@ cc_library_static { export_generated_headers: ["statslog_statsdtest.h"], shared_libs: [ "libstatssocket", - ] + "libstatspull", + ], } cc_library_static { @@ -185,7 +187,11 @@ cc_library_static { ], shared_libs: [ "libstatssocket", - ] + "libstatspull", + ], + export_shared_lib_headers: [ + "libstatspull", + ], } // ========= @@ -216,10 +222,6 @@ cc_binary { // address: true, //}, }, - debuggable: { - // Add a flag to enable stats log printing from statsd on debug builds. - cflags: ["-DVERY_VERBOSE_PRINTING"], - }, }, proto: { @@ -321,6 +323,8 @@ cc_test { "tests/metrics/metrics_test_helper.cpp", "tests/metrics/OringDurationTracker_test.cpp", "tests/metrics/ValueMetricProducer_test.cpp", + "tests/metrics/parsing_utils/config_update_utils_test.cpp", + "tests/metrics/parsing_utils/metrics_manager_util_test.cpp", "tests/MetricsManager_test.cpp", "tests/shell/ShellSubscriber_test.cpp", "tests/state/StateTracker_test.cpp", diff --git a/cmds/statsd/TEST_MAPPING b/cmds/statsd/TEST_MAPPING index 8dee073aca22..a7a4cf14182e 100644 --- a/cmds/statsd/TEST_MAPPING +++ b/cmds/statsd/TEST_MAPPING @@ -3,5 +3,15 @@ { "name" : "statsd_test" } + ], + + "postsubmit" : [ + { + "name" : "CtsStatsdHostTestCases" + }, + { + "name" : "GtsStatsdHostTestCases" + } ] -}
\ No newline at end of file + +} diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index e7b32c56551a..7bee4e2d1a36 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -120,10 +120,9 @@ static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outDat } } -void StatsLogProcessor::onAnomalyAlarmFired( +void StatsLogProcessor::processFiredAnomalyAlarmsLocked( const int64_t& timestampNs, unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) { - std::lock_guard<std::mutex> lock(mMetricsMutex); for (const auto& itr : mMetricsManagers) { itr.second->onAnomalyAlarmFired(timestampNs, alarmSet); } @@ -409,11 +408,9 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) { onWatchdogRollbackOccurredLocked(event); } -#ifdef VERY_VERBOSE_PRINTING if (mPrintAllLogs) { ALOGI("%s", event->ToString().c_str()); } -#endif resetIfConfigTtlExpiredLocked(eventElapsedTimeNs); // Hard-coded logic to update the isolated uid's in the uid-map. @@ -431,6 +428,20 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) { return; } + bool fireAlarm = false; + { + std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex); + if (mNextAnomalyAlarmTime != 0 && + MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) { + mNextAnomalyAlarmTime = 0; + VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs); + fireAlarm = true; + } + } + if (fireAlarm) { + informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs)); + } + int64_t curTimeSec = getElapsedRealtimeSec(); if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) { mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC); @@ -515,19 +526,35 @@ void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigK OnConfigUpdatedLocked(timestampNs, key, config); } -void StatsLogProcessor::OnConfigUpdatedLocked( - const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config) { +void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key, + const StatsdConfig& config, bool modularUpdate) { VLOG("Updated configuration for key %s", key.ToString().c_str()); - sp<MetricsManager> newMetricsManager = - new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager, - mAnomalyAlarmMonitor, mPeriodicAlarmMonitor); - if (newMetricsManager->isConfigValid()) { - newMetricsManager->init(); - mUidMap->OnConfigUpdated(key); - newMetricsManager->refreshTtl(timestampNs); - mMetricsManagers[key] = newMetricsManager; - VLOG("StatsdConfig valid"); + // Create new config if this is not a modular update or if this is a new config. + const auto& it = mMetricsManagers.find(key); + bool configValid = false; + if (!modularUpdate || it == mMetricsManagers.end()) { + sp<MetricsManager> newMetricsManager = + new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager, + mAnomalyAlarmMonitor, mPeriodicAlarmMonitor); + configValid = newMetricsManager->isConfigValid(); + if (configValid) { + newMetricsManager->init(); + mUidMap->OnConfigUpdated(key); + newMetricsManager->refreshTtl(timestampNs); + mMetricsManagers[key] = newMetricsManager; + VLOG("StatsdConfig valid"); + } } else { + // Preserve the existing MetricsManager, update necessary components and metadata in place. + configValid = it->second->updateConfig(config, mTimeBaseNs, timestampNs, + mAnomalyAlarmMonitor, mPeriodicAlarmMonitor); + if (configValid) { + // TODO(b/162323476): refresh TTL, ensure init() is handled properly. + mUidMap->OnConfigUpdated(key); + + } + } + if (!configValid) { // If there is any error in the config, don't use it. // Remove any existing config with the same key. ALOGE("StatsdConfig NOT valid"); @@ -1092,6 +1119,28 @@ void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) { mOnDiskDataConfigs.insert(key); } +void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = elapsedTimeMillis; +} + +void StatsLogProcessor::cancelAnomalyAlarm() { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = 0; +} + +void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) { + VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called"); + std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = + mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000)); + if (alarmSet.size() > 0) { + VLOG("Found periodic alarm fired."); + processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet); + } else { + ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled."); + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 23f2584655b0..383dbd9db2c1 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -66,11 +66,6 @@ public: const DumpLatency dumpLatency, ProtoOutputStream* proto); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ - void onAnomalyAlarmFired( - const int64_t& timestampNs, - unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */ void onPeriodicAlarmFired( const int64_t& timestampNs, @@ -139,15 +134,17 @@ public: int64_t getLastReportTimeNs(const ConfigKey& key); inline void setPrintLogs(bool enabled) { -#ifdef VERY_VERBOSE_PRINTING std::lock_guard<std::mutex> lock(mMetricsMutex); mPrintAllLogs = enabled; -#endif } // Add a specific config key to the possible configs to dump ASAP. void noteOnDiskData(const ConfigKey& key); + void setAnomalyAlarm(const int64_t timeMillis); + + void cancelAnomalyAlarm(); + private: // For testing only. inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const { @@ -160,6 +157,11 @@ private: mutable mutex mMetricsMutex; + // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled + // in the onLogEvent code path, which is locked by mMetricsMutex. + // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock. + mutable mutex mAnomalyAlarmMutex; + std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers; std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes; @@ -185,8 +187,8 @@ private: void resetIfConfigTtlExpiredLocked(const int64_t timestampNs); - void OnConfigUpdatedLocked( - const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config); + void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key, + const StatsdConfig& config, bool modularUpdate = false); void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs); @@ -250,6 +252,15 @@ private: // Reset the specified configs. void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs); + // An anomaly alarm should have fired. + // Check with anomaly alarm manager to find the alarms and process the result. + void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis); + + /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ + void processFiredAnomalyAlarmsLocked( + const int64_t& timestampNs, + unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); + // Function used to send a broadcast so that receiver for the config key can call getData // to retrieve the stored data. std::function<bool(const ConfigKey& key)> mSendBroadcast; @@ -276,9 +287,10 @@ private: //Last time we wrote metadata to disk. int64_t mLastMetadataWriteNs = 0; -#ifdef VERY_VERBOSE_PRINTING + // The time for the next anomaly alarm for alerts. + int64_t mNextAnomalyAlarmTime = 0; + bool mPrintAllLogs = false; -#endif FRIEND_TEST(StatsLogProcessorTest, TestOutOfOrderLogs); FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 322648229d0e..68c2dd56ef13 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -91,17 +91,13 @@ Status checkUid(uid_t expectedUid) { StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue) : mAnomalyAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, - [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) { - if (sc != nullptr) { - sc->setAnomalyAlarm(timeMillis); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) { + mProcessor->setAnomalyAlarm(timeMillis); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); }, - [](const shared_ptr<IStatsCompanionService>& sc) { - if (sc != nullptr) { - sc->cancelAnomalyAlarm(); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/) { + mProcessor->cancelAnomalyAlarm(); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); })), mPeriodicAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, @@ -484,7 +480,8 @@ void StatsService::print_cmd_help(int out) { dprintf(out, " Clear cached puller data.\n"); dprintf(out, "\n"); dprintf(out, "usage: adb shell cmd stats print-logs\n"); - dprintf(out, " Only works on eng build\n"); + dprintf(out, " Requires root privileges.\n"); + dprintf(out, " Can be disabled by calling adb shell cmd stats print-logs 0\n"); } status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) { @@ -865,18 +862,19 @@ status_t StatsService::cmd_clear_puller_cache(int out) { } status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) { - VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", AIBinder_getCallingPid(), - AIBinder_getCallingUid()); - if (checkPermission(kPermissionDump)) { - bool enabled = true; - if (args.size() >= 2) { - enabled = atoi(args[1].c_str()) != 0; - } - mProcessor->setPrintLogs(enabled); - return NO_ERROR; - } else { + Status status = checkUid(AID_ROOT); + if (!status.isOk()) { return PERMISSION_DENIED; } + + VLOG("StatsService::cmd_print_logs with pid %i, uid %i", AIBinder_getCallingPid(), + AIBinder_getCallingUid()); + bool enabled = true; + if (args.size() >= 2) { + enabled = atoi(args[1].c_str()) != 0; + } + mProcessor->setPrintLogs(enabled); + return NO_ERROR; } bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) { @@ -975,22 +973,6 @@ Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) { return Status::ok(); } -Status StatsService::informAnomalyAlarmFired() { - ENFORCE_UID(AID_SYSTEM); - - VLOG("StatsService::informAnomalyAlarmFired was called"); - int64_t currentTimeSec = getElapsedRealtimeSec(); - std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = - mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); - if (alarmSet.size() > 0) { - VLOG("Found an anomaly alarm that fired."); - mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet); - } else { - VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled."); - } - return Status::ok(); -} - Status StatsService::informAlarmForSubscriberTriggeringFired() { ENFORCE_UID(AID_SYSTEM); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 324ffbd65e51..479f4e87ec96 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -66,7 +66,6 @@ public: virtual Status systemRunning(); virtual Status statsCompanionReady(); virtual Status bootCompleted(); - virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); virtual Status informAlarmForSubscriberTriggeringFired(); @@ -404,6 +403,10 @@ private: FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket); + + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); }; } // namespace statsd diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index d0d3d285ada2..e6e22bac05d4 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -485,6 +485,9 @@ message Atom { NetworkTetheringReported network_tethering_reported = 303 [(module) = "network_tethering"]; ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"]; + UIInteractionFrameInfoReported ui_interaction_frame_info_reported = + 305 [(module) = "framework"]; + UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"]; // StatsdStats tracks platform atoms with ids upto 500. // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value. @@ -583,9 +586,10 @@ message Atom { SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"]; SettingSnapshot setting_snapshot = 10080 [(module) = "framework"]; BlobInfo blob_info = 10081 [(module) = "framework"]; - DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"]; + DataUsageBytesTransfer data_usage_bytes_transfer = + 10082 [(module) = "framework", (truncate_timestamp) = true]; BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered = - 10083 [(module) = "framework"]; + 10083 [(module) = "framework", (truncate_timestamp) = true]; DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"]; GeneralExternalStorageAccessStats general_external_storage_access_stats = 10085 [(module) = "mediaprovider"]; @@ -4003,7 +4007,7 @@ message Notification { optional bool is_group_summary = 5; // The section of the shade that the notification is in. - // See NotificationSectionsManager.PriorityBucket. + // See SystemUI Notifications.proto. enum NotificationSection { SECTION_UNKNOWN = 0; SECTION_HEADS_UP = 1; @@ -4011,6 +4015,7 @@ message Notification { SECTION_PEOPLE = 3; SECTION_ALERTING = 4; SECTION_SILENT = 5; + SECTION_FOREGROUND_SERVICE = 6; } optional NotificationSection section = 6; } @@ -4244,6 +4249,19 @@ message BinaryPushStateChanged { INSTALL_FAILURE_STATE_MISMATCH = 24; INSTALL_FAILURE_COMMIT = 25; REBOOT_TRIGGERED = 26; + // Logged after INSTALL_REQUESTED for devices installing a train that + // contains no module requiring reboot. + REBOOT_NOT_REQUIRED = 27; + // Logged after INSTALL_REQUESTED for devices that are installing a train + // which requires reboot and eligible for soft restart. + SOFT_RESTART_ELIGIBLE = 28; + // Logged after INSTALL_REQUESTED for devices that are installing a train + // which requires reboot and eligible for notification restart. + NOTIFICATION_RESTART_ELIGIBLE = 29; + // Logged after INSTALL_REQUESTED for devices that are installing a train + // which requires reboot and not eligible for any reboot promotion strategy + // (e.g. soft restart, notification restart). + NO_REBOOT_PROMOTION_STRATEGY_ELIGIBLE = 30; } optional State state = 6; // Possible experiment ids for monitoring this push. @@ -4574,7 +4592,7 @@ message GeneralExternalStorageAccessStats { // Includes file path and ContentResolver accesses optional uint32 secondary_storage_accesses = 4; // Comma-separated list of mime types that were accessed. - optional MimeTypes mime_types_accessed = 5; + optional MimeTypes mime_types_accessed = 5 [(log_mode) = MODE_BYTES]; } /** @@ -5040,6 +5058,54 @@ message BlobOpened{ optional Result result = 4; } +/** + * Event to track Jank for various system interactions. + * + * Logged from: + * frameworks/base/core/java/android/os/aot/FrameTracker.java + */ +message UIInteractionFrameInfoReported { + enum InteractionType { + UNKNOWN = 0; + NOTIFICATION_SHADE_SWIPE = 1; + } + + optional InteractionType interaction_type = 1; + + // Number of frames rendered during the interaction. + optional int64 total_frames = 2; + + // Number of frames that were skipped in rendering during the interaction. + optional int64 missed_frames = 3; + + // Maximum time it took to render a single frame during the interaction. + optional int64 max_frame_time_nanos = 4; +} + +/** + * Event to track various latencies in SystemUI. + * + * Logged from: + * frameworks/base/core/java/com/android/internal/util/LatencyTracker.java + */ +message UIActionLatencyReported { + enum ActionType { + UNKNOWN = 0; + ACTION_EXPAND_PANEL = 1; + ACTION_TOGGLE_RECENTS = 2; + ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 3; + ACTION_CHECK_CREDENTIAL = 4; + ACTION_CHECK_CREDENTIAL_UNLOCKED = 5; + ACTION_TURN_ON_SCREEN = 6; + ACTION_ROTATE_SCREEN = 7; + ACTION_FACE_WAKE_AND_UNLOCK = 8; + } + + optional ActionType action = 1; + + optional int64 latency_millis = 2; +} + ////////////////////////////////////////////////////////////////////// // Pulled atoms below this line // ////////////////////////////////////////////////////////////////////// @@ -6164,7 +6230,7 @@ message ProcessStatsAvailablePagesProto { * Pulled from ProcessStatsService.java */ message ProcStats { - optional ProcessStatsSectionProto proc_stats_section = 1; + optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES]; // Data pulled from device into this is sometimes sharded across multiple atoms to work around // a size limit. When this happens, this shard ID will contain an increasing 1-indexed integer // with the number of this shard. @@ -6175,7 +6241,7 @@ message ProcStats { * Pulled from ProcessStatsService.java */ message ProcStatsPkgProc { - optional ProcessStatsSectionProto proc_stats_section = 1; + optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES]; } // Next Tag: 2 @@ -6193,7 +6259,7 @@ message NotificationRemoteViewsProto { * Pulled from NotificationManagerService.java */ message NotificationRemoteViews { - optional NotificationRemoteViewsProto notification_remote_views = 1; + optional NotificationRemoteViewsProto notification_remote_views = 1 [(log_mode) = MODE_BYTES]; } /** @@ -6261,7 +6327,7 @@ message DNDModeProto { // May also be "MANUAL_RULE" to indicate app-activation of the manual rule. optional string id = 5; optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other - optional DNDPolicyProto policy = 7; + optional DNDPolicyProto policy = 7 [(log_mode) = MODE_BYTES]; } /** @@ -6426,7 +6492,7 @@ message PowerProfileProto { * Pulled from PowerProfile.java */ message PowerProfile { - optional PowerProfileProto power_profile = 1; + optional PowerProfileProto power_profile = 1 [(log_mode) = MODE_BYTES]; } /** @@ -8121,7 +8187,7 @@ message DeviceIdentifierAccessDenied { message TrainInfo { optional int64 train_version_code = 1; - optional TrainExperimentIds train_experiment_id = 2; + optional TrainExperimentIds train_experiment_id = 2 [(log_mode) = MODE_BYTES]; optional string train_name = 3; @@ -11169,8 +11235,8 @@ message BlobInfo { optional int64 expiry_timestamp_millis = 3; // List of committers of this Blob - optional BlobCommitterListProto committers = 4; + optional BlobCommitterListProto committers = 4 [(log_mode) = MODE_BYTES]; // List of leasees of this Blob - optional BlobLeaseeListProto leasees = 5; + optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES]; } diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp index e9875baf58c7..4574b2e34547 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp +++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp @@ -25,8 +25,9 @@ namespace statsd { using std::unordered_map; using std::vector; -CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index) - : ConditionTracker(id, index) { +CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index, + const uint64_t protoHash) + : ConditionTracker(id, index, protoHash) { VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId); } @@ -38,9 +39,23 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf const vector<sp<ConditionTracker>>& allConditionTrackers, const unordered_map<int64_t, int>& conditionIdIndexMap, vector<bool>& stack, - vector<ConditionState>& initialConditionCache) { + vector<ConditionState>& conditionCache) { VLOG("Combination predicate init() %lld", (long long)mConditionId); if (mInitialized) { + // All the children are guaranteed to be initialized, but the recursion is needed to + // fill the conditionCache properly, since another combination condition or metric + // might rely on this. The recursion is needed to compute the current condition. + + // Init is called instead of isConditionMet so that the ConditionKey can be filled with the + // default key for sliced conditions, since we do not know all indirect descendants here. + for (const int childIndex : mChildren) { + if (conditionCache[childIndex] == ConditionState::kNotEvaluated) { + allConditionTrackers[childIndex]->init(allConditionConfig, allConditionTrackers, + conditionIdIndexMap, stack, conditionCache); + } + } + conditionCache[mIndex] = + evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); return true; } @@ -74,9 +89,8 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf return false; } - bool initChildSucceeded = - childTracker->init(allConditionConfig, allConditionTrackers, conditionIdIndexMap, - stack, initialConditionCache); + bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers, + conditionIdIndexMap, stack, conditionCache); if (!initChildSucceeded) { ALOGW("Child initialization failed %lld ", (long long)child); @@ -92,14 +106,14 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf mUnSlicedChildren.push_back(childIndex); } mChildren.push_back(childIndex); - mTrackerIndex.insert(childTracker->getLogTrackerIndex().begin(), - childTracker->getLogTrackerIndex().end()); + mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(), + childTracker->getAtomMatchingTrackerIndex().end()); } - mUnSlicedPartCondition = evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation, - initialConditionCache); - initialConditionCache[mIndex] = - evaluateCombinationCondition(mChildren, mLogicalOperation, initialConditionCache); + mUnSlicedPartCondition = + evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation, conditionCache); + conditionCache[mIndex] = + evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); // unmark this node in the recursion stack. stack[mIndex] = false; @@ -109,6 +123,49 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf return true; } +bool CombinationConditionTracker::onConfigUpdated( + const vector<Predicate>& allConditionProtos, const int index, + const vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const unordered_map<int64_t, int>& conditionTrackerMap) { + ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap); + mTrackerIndex.clear(); + mChildren.clear(); + mUnSlicedChildren.clear(); + mSlicedChildren.clear(); + Predicate_Combination combinationCondition = allConditionProtos[mIndex].combination(); + + for (const int64_t child : combinationCondition.predicate()) { + const auto& it = conditionTrackerMap.find(child); + + if (it == conditionTrackerMap.end()) { + ALOGW("Predicate %lld not found in the config", (long long)child); + return false; + } + + int childIndex = it->second; + const sp<ConditionTracker>& childTracker = allConditionTrackers[childIndex]; + + // Ensures that the child's tracker indices are updated. + if (!childTracker->onConfigUpdated(allConditionProtos, childIndex, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap)) { + ALOGW("Child update failed %lld ", (long long)child); + return false; + } + + if (allConditionTrackers[childIndex]->isSliced()) { + mSlicedChildren.push_back(childIndex); + } else { + mUnSlicedChildren.push_back(childIndex); + } + mChildren.push_back(childIndex); + mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(), + childTracker->getAtomMatchingTrackerIndex().end()); + } + return true; +} + void CombinationConditionTracker::isConditionMet( const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, const bool isPartialLink, diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h index 39ff0ab03266..672d61c82268 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.h +++ b/cmds/statsd/src/condition/CombinationConditionTracker.h @@ -24,16 +24,21 @@ namespace android { namespace os { namespace statsd { -class CombinationConditionTracker : public virtual ConditionTracker { +class CombinationConditionTracker : public ConditionTracker { public: - CombinationConditionTracker(const int64_t& id, const int index); + CombinationConditionTracker(const int64_t& id, const int index, const uint64_t protoHash); ~CombinationConditionTracker(); bool init(const std::vector<Predicate>& allConditionConfig, const std::vector<sp<ConditionTracker>>& allConditionTrackers, const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack, - std::vector<ConditionState>& initialConditionCache) override; + std::vector<ConditionState>& conditionCache) override; + + bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) override; void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, @@ -102,6 +107,7 @@ private: std::vector<int> mSlicedChildren; std::vector<int> mUnSlicedChildren; + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h index 62736c8160bb..3bf4e636be89 100644 --- a/cmds/statsd/src/condition/ConditionTracker.h +++ b/cmds/statsd/src/condition/ConditionTracker.h @@ -18,7 +18,7 @@ #include "condition/condition_util.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" -#include "matchers/LogMatchingTracker.h" +#include "matchers/AtomMatchingTracker.h" #include "matchers/matcher_util.h" #include <utils/RefBase.h> @@ -31,38 +31,59 @@ namespace statsd { class ConditionTracker : public virtual RefBase { public: - ConditionTracker(const int64_t& id, const int index) + ConditionTracker(const int64_t& id, const int index, const uint64_t protoHash) : mConditionId(id), mIndex(index), mInitialized(false), mTrackerIndex(), mUnSlicedPartCondition(ConditionState::kUnknown), - mSliced(false){}; + mSliced(false), + mProtoHash(protoHash){}; virtual ~ConditionTracker(){}; - inline const int64_t& getId() { return mConditionId; } - // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also // be done in the constructor, but we do it separately because (1) easy to return a bool to // indicate whether the initialization is successful. (2) makes unit test easier. + // This function can also be called on config updates, in which case it does nothing other than + // fill the condition cache with the current condition. // allConditionConfig: the list of all Predicate config from statsd_config. // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also - // need to call init() on children conditions) + // need to call init() on child conditions) // conditionIdIndexMap: the mapping from condition id to its index. // stack: a bit map to keep track which nodes have been visited on the stack in the recursion. - // initialConditionCache: tracks initial conditions of all ConditionTrackers. + // conditionCache: tracks initial conditions of all ConditionTrackers. returns the + // current condition if called on a config update. virtual bool init(const std::vector<Predicate>& allConditionConfig, const std::vector<sp<ConditionTracker>>& allConditionTrackers, const std::unordered_map<int64_t, int>& conditionIdIndexMap, - std::vector<bool>& stack, - std::vector<ConditionState>& initialConditionCache) = 0; + std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0; + + // Update appropriate state on config updates. Primarily, all indices need to be updated. + // This predicate and all of its children are guaranteed to be preserved across the update. + // This function is recursive and will call onConfigUpdated on child conditions. It does not + // manage cycle detection since all preserved conditions should not have any cycles. + // + // allConditionProtos: the new predicates. + // index: the new index of this tracker in allConditionProtos and allConditionTrackers. + // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also + // need to call onConfigUpdated() on child conditions) + // [atomMatchingTrackerMap]: map of atom matcher id to index after the config update + // [conditionTrackerMap]: map of condition tracker id to index after the config update. + // returns whether or not the update is successful + virtual bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) { + mIndex = index; + return true; + } // evaluate current condition given the new event. // event: the new log event - // eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process - // event before ConditionTrackers, because ConditionTracker depends on - // LogMatchingTrackers. + // eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always + // process event before ConditionTrackers, because ConditionTracker depends + // on AtomMatchingTrackers. // mAllConditions: the list of all ConditionTracker // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event. // conditionChanged: the bit map to record whether the condition has changed. @@ -88,8 +109,8 @@ public: const bool isPartialLink, std::vector<ConditionState>& conditionCache) const = 0; - // return the list of LogMatchingTracker index that this ConditionTracker uses. - virtual const std::set<int>& getLogTrackerIndex() const { + // return the list of AtomMatchingTracker index that this ConditionTracker uses. + virtual const std::set<int>& getAtomMatchingTrackerIndex() const { return mTrackerIndex; } @@ -110,6 +131,10 @@ public: return mConditionId; } + inline uint64_t getProtoHash() const { + return mProtoHash; + } + virtual void getTrueSlicedDimensions( const std::vector<sp<ConditionTracker>>& allConditions, std::set<HashableDimensionKey>* dimensions) const = 0; @@ -131,12 +156,12 @@ protected: const int64_t mConditionId; // the index of this condition in the manager's condition list. - const int mIndex; + int mIndex; // if it's properly initialized. bool mInitialized; - // the list of LogMatchingTracker index that this ConditionTracker uses. + // the list of AtomMatchingTracker index that this ConditionTracker uses. std::set<int> mTrackerIndex; // This variable is only used for CombinationConditionTrackers. @@ -149,6 +174,12 @@ protected: ConditionState mUnSlicedPartCondition; bool mSliced; + + // Hash of the Predicate's proto bytes from StatsdConfig. + // Used to determine if the definition of this condition has changed across a config update. + const uint64_t mProtoHash; + + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index efb4d4989425..1dcc8f96131a 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -27,54 +27,21 @@ namespace statsd { using std::unordered_map; SimpleConditionTracker::SimpleConditionTracker( - const ConfigKey& key, const int64_t& id, const int index, + const ConfigKey& key, const int64_t& id, const uint64_t protoHash, const int index, const SimplePredicate& simplePredicate, - const unordered_map<int64_t, int>& trackerNameIndexMap) - : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) { + const unordered_map<int64_t, int>& atomMatchingTrackerMap) + : ConditionTracker(id, index, protoHash), + mConfigKey(key), + mContainANYPositionInInternalDimensions(false) { VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId); mCountNesting = simplePredicate.count_nesting(); - if (simplePredicate.has_start()) { - auto pair = trackerNameIndexMap.find(simplePredicate.start()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start()); - return; - } - mStartLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStartLogMatcherIndex); - } else { - mStartLogMatcherIndex = -1; - } - - if (simplePredicate.has_stop()) { - auto pair = trackerNameIndexMap.find(simplePredicate.stop()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop()); - return; - } - mStopLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStopLogMatcherIndex); - } else { - mStopLogMatcherIndex = -1; - } - - if (simplePredicate.has_stop_all()) { - auto pair = trackerNameIndexMap.find(simplePredicate.stop_all()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all()); - return; - } - mStopAllLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStopAllLogMatcherIndex); - } else { - mStopAllLogMatcherIndex = -1; - } + setMatcherIndices(simplePredicate, atomMatchingTrackerMap); if (simplePredicate.has_dimensions()) { translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions); if (mOutputDimensions.size() > 0) { mSliced = true; - mDimensionTag = mOutputDimensions[0].mMatcher.getTag(); } mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions()); } @@ -95,14 +62,70 @@ SimpleConditionTracker::~SimpleConditionTracker() { bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig, const vector<sp<ConditionTracker>>& allConditionTrackers, const unordered_map<int64_t, int>& conditionIdIndexMap, - vector<bool>& stack, - vector<ConditionState>& initialConditionCache) { + vector<bool>& stack, vector<ConditionState>& conditionCache) { // SimpleConditionTracker does not have dependency on other conditions, thus we just return // if the initialization was successful. - initialConditionCache[mIndex] = mInitialValue; + ConditionKey conditionKey; + if (mSliced) { + conditionKey[mConditionId] = DEFAULT_DIMENSION_KEY; + } + isConditionMet(conditionKey, allConditionTrackers, mSliced, conditionCache); return mInitialized; } +bool SimpleConditionTracker::onConfigUpdated( + const vector<Predicate>& allConditionProtos, const int index, + const vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const unordered_map<int64_t, int>& conditionTrackerMap) { + ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap); + setMatcherIndices(allConditionProtos[index].simple_predicate(), atomMatchingTrackerMap); + return true; +} + +void SimpleConditionTracker::setMatcherIndices( + const SimplePredicate& simplePredicate, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + mTrackerIndex.clear(); + if (simplePredicate.has_start()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.start()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start()); + return; + } + mStartLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStartLogMatcherIndex); + } else { + mStartLogMatcherIndex = -1; + } + + if (simplePredicate.has_stop()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.stop()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop()); + return; + } + mStopLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStopLogMatcherIndex); + } else { + mStopLogMatcherIndex = -1; + } + + if (simplePredicate.has_stop_all()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.stop_all()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Stop all matcher %lld found in the config", + (long long)simplePredicate.stop_all()); + return; + } + mStopAllLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStopAllLogMatcherIndex); + } else { + mStopAllLogMatcherIndex = -1; + } +} + void SimpleConditionTracker::dumpState() { VLOG("%lld DUMP:", (long long)mConditionId); for (const auto& pair : mSlicedConditionState) { diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h index ea7f87bde2b8..7a8b40108448 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.h +++ b/cmds/statsd/src/condition/SimpleConditionTracker.h @@ -27,18 +27,23 @@ namespace android { namespace os { namespace statsd { -class SimpleConditionTracker : public virtual ConditionTracker { +class SimpleConditionTracker : public ConditionTracker { public: - SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index, - const SimplePredicate& simplePredicate, - const std::unordered_map<int64_t, int>& trackerNameIndexMap); + SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const uint64_t protoHash, + const int index, const SimplePredicate& simplePredicate, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap); ~SimpleConditionTracker(); bool init(const std::vector<Predicate>& allConditionConfig, const std::vector<sp<ConditionTracker>>& allConditionTrackers, const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack, - std::vector<ConditionState>& initialConditionCache) override; + std::vector<ConditionState>& conditionCache) override; + + bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) override; void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, @@ -112,10 +117,11 @@ private: std::set<HashableDimensionKey> mLastChangedToTrueDimensions; std::set<HashableDimensionKey> mLastChangedToFalseDimensions; - int mDimensionTag; - std::map<HashableDimensionKey, int> mSlicedConditionState; + void setMatcherIndices(const SimplePredicate& predicate, + const std::unordered_map<int64_t, int>& logTrackerMap); + void handleStopAll(std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache); @@ -129,6 +135,7 @@ private: FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition); FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim); FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll); + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 8a9ec7456e55..46c377037542 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -92,63 +92,43 @@ StatsPullerManager::StatsPullerManager() } bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs, - vector<shared_ptr<LogEvent>>* data, bool useUids) { + vector<shared_ptr<LogEvent>>* data) { std::lock_guard<std::mutex> _l(mLock); - return PullLocked(tagId, configKey, eventTimeNs, data, useUids); + return PullLocked(tagId, configKey, eventTimeNs, data); } bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids) { + vector<std::shared_ptr<LogEvent>>* data) { std::lock_guard<std::mutex> _l(mLock); - return PullLocked(tagId, uids, eventTimeNs, data, useUids); + return PullLocked(tagId, uids, eventTimeNs, data); } bool StatsPullerManager::PullLocked(int tagId, const ConfigKey& configKey, - const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data, - bool useUids) { + const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data) { vector<int32_t> uids; - if (useUids) { - auto uidProviderIt = mPullUidProviders.find(configKey); - if (uidProviderIt == mPullUidProviders.end()) { - ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId, - configKey.ToString().c_str()); - StatsdStats::getInstance().notePullUidProviderNotFound(tagId); - return false; - } - sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote(); - if (pullUidProvider == nullptr) { - ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId, - configKey.ToString().c_str()); - StatsdStats::getInstance().notePullUidProviderNotFound(tagId); - return false; - } - uids = pullUidProvider->getPullAtomUids(tagId); + const auto& uidProviderIt = mPullUidProviders.find(configKey); + if (uidProviderIt == mPullUidProviders.end()) { + ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId, + configKey.ToString().c_str()); + StatsdStats::getInstance().notePullUidProviderNotFound(tagId); + return false; } - return PullLocked(tagId, uids, eventTimeNs, data, useUids); + sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote(); + if (pullUidProvider == nullptr) { + ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId, + configKey.ToString().c_str()); + StatsdStats::getInstance().notePullUidProviderNotFound(tagId); + return false; + } + uids = pullUidProvider->getPullAtomUids(tagId); + return PullLocked(tagId, uids, eventTimeNs, data); } bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids, - const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data, - bool useUids) { + const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data) { VLOG("Initiating pulling %d", tagId); - if (useUids) { - for (int32_t uid : uids) { - PullerKey key = {.atomTag = tagId, .uid = uid}; - auto pullerIt = kAllPullAtomInfo.find(key); - if (pullerIt != kAllPullAtomInfo.end()) { - bool ret = pullerIt->second->Pull(eventTimeNs, data); - VLOG("pulled %zu items", data->size()); - if (!ret) { - StatsdStats::getInstance().notePullFailed(tagId); - } - return ret; - } - } - StatsdStats::getInstance().notePullerNotFound(tagId); - ALOGW("StatsPullerManager: Unknown tagId %d", tagId); - return false; // Return early since we don't know what to pull. - } else { - PullerKey key = {.atomTag = tagId, .uid = -1}; + for (int32_t uid : uids) { + PullerKey key = {.atomTag = tagId, .uid = uid}; auto pullerIt = kAllPullAtomInfo.find(key); if (pullerIt != kAllPullAtomInfo.end()) { bool ret = pullerIt->second->Pull(eventTimeNs, data); @@ -158,9 +138,10 @@ bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids, } return ret; } - ALOGW("StatsPullerManager: Unknown tagId %d", tagId); - return false; // Return early since we don't know what to pull. } + StatsdStats::getInstance().notePullerNotFound(tagId); + ALOGW("StatsPullerManager: Unknown tagId %d", tagId); + return false; // Return early since we don't know what to pull. } bool StatsPullerManager::PullerForMatcherExists(int tagId) const { @@ -352,8 +333,7 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) { void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t atomTag, const int64_t coolDownNs, const int64_t timeoutNs, const vector<int32_t>& additiveFields, - const shared_ptr<IPullAtomCallback>& callback, - bool useUid) { + const shared_ptr<IPullAtomCallback>& callback) { std::lock_guard<std::mutex> _l(mLock); VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); @@ -368,16 +348,15 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a sp<StatsCallbackPuller> puller = new StatsCallbackPuller(atomTag, callback, actualCoolDownNs, actualTimeoutNs, additiveFields); - PullerKey key = {.atomTag = atomTag, .uid = useUid ? uid : -1}; + PullerKey key = {.atomTag = atomTag, .uid = uid}; AIBinder_linkToDeath(callback->asBinder().get(), mPullAtomCallbackDeathRecipient.get(), new PullAtomCallbackDeathCookie(this, key, puller)); kAllPullAtomInfo[key] = puller; } -void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag, - bool useUids) { +void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag) { std::lock_guard<std::mutex> _l(mLock); - PullerKey key = {.atomTag = atomTag, .uid = useUids ? uid : -1}; + PullerKey key = {.atomTag = atomTag, .uid = uid}; if (kAllPullAtomInfo.find(key) != kAllPullAtomInfo.end()) { StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false); diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 194a0f5edba8..489cbdbe5400 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -102,11 +102,11 @@ public: // If the metric wants to make any change to the data, like timestamps, they // should make a copy as this data may be shared with multiple metrics. virtual bool Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids = true); + vector<std::shared_ptr<LogEvent>>* data); // Same as above, but directly specify the allowed uids to pull from. virtual bool Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids = true); + vector<std::shared_ptr<LogEvent>>* data); // Clear pull data cache immediately. int ForceClearPullerCache(); @@ -118,10 +118,9 @@ public: void RegisterPullAtomCallback(const int uid, const int32_t atomTag, const int64_t coolDownNs, const int64_t timeoutNs, const vector<int32_t>& additiveFields, - const shared_ptr<IPullAtomCallback>& callback, - bool useUid = true); + const shared_ptr<IPullAtomCallback>& callback); - void UnregisterPullAtomCallback(const int uid, const int32_t atomTag, bool useUids = true); + void UnregisterPullAtomCallback(const int uid, const int32_t atomTag); std::map<const PullerKey, sp<StatsPuller>> kAllPullAtomInfo; @@ -153,10 +152,10 @@ private: std::map<ConfigKey, wp<PullUidProvider>> mPullUidProviders; bool PullLocked(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids = true); + vector<std::shared_ptr<LogEvent>>* data); bool PullLocked(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids); + vector<std::shared_ptr<LogEvent>>* data); // locks for data receiver and StatsCompanionService changes std::mutex mLock; diff --git a/cmds/statsd/src/hash.h b/cmds/statsd/src/hash.h index cfe869f60202..bd6b0cd47eaf 100644 --- a/cmds/statsd/src/hash.h +++ b/cmds/statsd/src/hash.h @@ -22,6 +22,7 @@ namespace android { namespace os { namespace statsd { +// Uses murmur2 hashing algorithm. extern uint32_t Hash32(const char *data, size_t n, uint32_t seed); extern uint64_t Hash64(const char* data, size_t n, uint64_t seed); diff --git a/cmds/statsd/src/matchers/AtomMatchingTracker.h b/cmds/statsd/src/matchers/AtomMatchingTracker.h new file mode 100644 index 000000000000..c1384972464c --- /dev/null +++ b/cmds/statsd/src/matchers/AtomMatchingTracker.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ATOM_MATCHING_TRACKER_H +#define ATOM_MATCHING_TRACKER_H + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "logd/LogEvent.h" +#include "matchers/matcher_util.h" + +#include <utils/RefBase.h> + +#include <set> +#include <unordered_map> +#include <vector> + +namespace android { +namespace os { +namespace statsd { + +class AtomMatchingTracker : public virtual RefBase { +public: + AtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash) + : mId(id), mIndex(index), mInitialized(false), mProtoHash(protoHash){}; + + virtual ~AtomMatchingTracker(){}; + + // Initialize this AtomMatchingTracker. + // allAtomMatchers: the list of the AtomMatcher proto config. This is needed because we don't + // store the proto object in memory. We only need it during initilization. + // allAtomMatchingTrackers: the list of the AtomMatchingTracker objects. It's a one-to-one + // mapping with allAtomMatchers. This is needed because the + // initialization is done recursively for + // CombinationAtomMatchingTrackers using DFS. + // stack: a bit map to record which matcher has been visited on the stack. This is for detecting + // circle dependency. + virtual bool init(const std::vector<AtomMatcher>& allAtomMatchers, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& matcherMap, + std::vector<bool>& stack) = 0; + + // Update appropriate state on config updates. Primarily, all indices need to be updated. + // This matcher and all of its children are guaranteed to be preserved across the update. + // matcher: the AtomMatcher proto from the config. + // index: the index of this matcher in mAllAtomMatchingTrackers. + // atomMatchingTrackerMap: map from matcher id to index in mAllAtomMatchingTrackers + virtual bool onConfigUpdated( + const AtomMatcher& matcher, const int index, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) = 0; + + // Called when a log event comes. + // event: the log event. + // allAtomMatchingTrackers: the list of all AtomMatchingTrackers. This is needed because the log + // processing is done recursively. + // matcherResults: The cached results for all matchers for this event. Parent matchers can + // directly access the children's matching results if they have been evaluated. + // Otherwise, call children matchers' onLogEvent. + virtual void onLogEvent(const LogEvent& event, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + std::vector<MatchingState>& matcherResults) = 0; + + // Get the tagIds that this matcher cares about. The combined collection is stored + // in MetricMananger, so that we can pass any LogEvents that are not interest of us. It uses + // some memory but hopefully it can save us much CPU time when there is flood of events. + virtual const std::set<int>& getAtomIds() const { + return mAtomIds; + } + + int64_t getId() const { + return mId; + } + + uint64_t getProtoHash() const { + return mProtoHash; + } + +protected: + // Name of this matching. We don't really need the name, but it makes log message easy to debug. + const int64_t mId; + + // Index of this AtomMatchingTracker in MetricsManager's container. + int mIndex; + + // Whether this AtomMatchingTracker has been properly initialized. + bool mInitialized; + + // The collection of the event tag ids that this AtomMatchingTracker cares. So we can quickly + // return kNotMatched when we receive an event with an id not in the list. This is especially + // useful when we have a complex CombinationAtomMatchingTracker. + std::set<int> mAtomIds; + + // Hash of the AtomMatcher's proto bytes from StatsdConfig. + // Used to determine if the definition of this matcher has changed across a config update. + const uint64_t mProtoHash; + + FRIEND_TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerSimple); + FRIEND_TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination); + FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers); +}; + +} // namespace statsd +} // namespace os +} // namespace android + +#endif // ATOM_MATCHING_TRACKER_H diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp index b94a9572113e..45685ce5bfee 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp @@ -16,7 +16,8 @@ #include "Log.h" -#include "CombinationLogMatchingTracker.h" +#include "CombinationAtomMatchingTracker.h" + #include "matchers/matcher_util.h" namespace android { @@ -27,17 +28,18 @@ using std::set; using std::unordered_map; using std::vector; -CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index) - : LogMatchingTracker(id, index) { +CombinationAtomMatchingTracker::CombinationAtomMatchingTracker(const int64_t& id, const int index, + const uint64_t protoHash) + : AtomMatchingTracker(id, index, protoHash) { } -CombinationLogMatchingTracker::~CombinationLogMatchingTracker() { +CombinationAtomMatchingTracker::~CombinationAtomMatchingTracker() { } -bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers, - const vector<sp<LogMatchingTracker>>& allTrackers, - const unordered_map<int64_t, int>& matcherMap, - vector<bool>& stack) { +bool CombinationAtomMatchingTracker::init( + const vector<AtomMatcher>& allAtomMatchers, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& matcherMap, vector<bool>& stack) { if (mInitialized) { return true; } @@ -45,7 +47,7 @@ bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatche // mark this node as visited in the recursion stack. stack[mIndex] = true; - AtomMatcher_Combination matcher = allLogMatchers[mIndex].combination(); + AtomMatcher_Combination matcher = allAtomMatchers[mIndex].combination(); // LogicalOperation is missing in the config if (!matcher.has_operation()) { @@ -73,14 +75,15 @@ bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatche return false; } - if (!allTrackers[childIndex]->init(allLogMatchers, allTrackers, matcherMap, stack)) { + if (!allAtomMatchingTrackers[childIndex]->init(allAtomMatchers, allAtomMatchingTrackers, + matcherMap, stack)) { ALOGW("child matcher init failed %lld", (long long)child); return false; } mChildren.push_back(childIndex); - const set<int>& childTagIds = allTrackers[childIndex]->getAtomIds(); + const set<int>& childTagIds = allAtomMatchingTrackers[childIndex]->getAtomIds(); mAtomIds.insert(childTagIds.begin(), childTagIds.end()); } @@ -90,9 +93,26 @@ bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatche return true; } -void CombinationLogMatchingTracker::onLogEvent(const LogEvent& event, - const vector<sp<LogMatchingTracker>>& allTrackers, - vector<MatchingState>& matcherResults) { +bool CombinationAtomMatchingTracker::onConfigUpdated( + const AtomMatcher& matcher, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + mIndex = index; + mChildren.clear(); + AtomMatcher_Combination combinationMatcher = matcher.combination(); + for (const int64_t child : combinationMatcher.matcher()) { + const auto& pair = atomMatchingTrackerMap.find(child); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Matcher %lld not found in the config", (long long)child); + return false; + } + mChildren.push_back(pair->second); + } + return true; +} + +void CombinationAtomMatchingTracker::onLogEvent( + const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + vector<MatchingState>& matcherResults) { // this event has been processed. if (matcherResults[mIndex] != MatchingState::kNotComputed) { return; @@ -106,8 +126,8 @@ void CombinationLogMatchingTracker::onLogEvent(const LogEvent& event, // evaluate children matchers if they haven't been evaluated. for (const int childIndex : mChildren) { if (matcherResults[childIndex] == MatchingState::kNotComputed) { - const sp<LogMatchingTracker>& child = allTrackers[childIndex]; - child->onLogEvent(event, allTrackers, matcherResults); + const sp<AtomMatchingTracker>& child = allAtomMatchingTrackers[childIndex]; + child->onLogEvent(event, allAtomMatchingTrackers, matcherResults); } } diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h index 55bc46059fc1..3160448b6c76 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef COMBINATION_LOG_MATCHING_TRACKER_H -#define COMBINATION_LOG_MATCHING_TRACKER_H +#ifndef COMBINATION_ATOM_MATCHING_TRACKER_H +#define COMBINATION_ATOM_MATCHING_TRACKER_H #include <unordered_map> #include <vector> -#include "LogMatchingTracker.h" + +#include "AtomMatchingTracker.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" namespace android { @@ -26,28 +27,32 @@ namespace os { namespace statsd { // Represents a AtomMatcher_Combination in the StatsdConfig. -class CombinationLogMatchingTracker : public virtual LogMatchingTracker { +class CombinationAtomMatchingTracker : public AtomMatchingTracker { public: - CombinationLogMatchingTracker(const int64_t& id, const int index); + CombinationAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash); + + bool init(const std::vector<AtomMatcher>& allAtomMatchers, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& matcherMap, std::vector<bool>& stack); - bool init(const std::vector<AtomMatcher>& allLogMatchers, - const std::vector<sp<LogMatchingTracker>>& allTrackers, - const std::unordered_map<int64_t, int>& matcherMap, - std::vector<bool>& stack); + bool onConfigUpdated(const AtomMatcher& matcher, const int index, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override; - ~CombinationLogMatchingTracker(); + ~CombinationAtomMatchingTracker(); void onLogEvent(const LogEvent& event, - const std::vector<sp<LogMatchingTracker>>& allTrackers, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, std::vector<MatchingState>& matcherResults) override; private: LogicalOperation mLogicalOperation; std::vector<int> mChildren; + + FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers); }; } // namespace statsd } // namespace os } // namespace android -#endif // COMBINATION_LOG_MATCHING_TRACKER_H +#endif // COMBINATION_ATOM_MATCHING_TRACKER_H diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.h b/cmds/statsd/src/matchers/EventMatcherWizard.h index 57ec2b35ba32..5d780f2423d8 100644 --- a/cmds/statsd/src/matchers/EventMatcherWizard.h +++ b/cmds/statsd/src/matchers/EventMatcherWizard.h @@ -16,7 +16,7 @@ #pragma once -#include "LogMatchingTracker.h" +#include "AtomMatchingTracker.h" namespace android { namespace os { @@ -25,7 +25,7 @@ namespace statsd { class EventMatcherWizard : public virtual android::RefBase { public: EventMatcherWizard(){}; // for testing - EventMatcherWizard(const std::vector<sp<LogMatchingTracker>>& eventTrackers) + EventMatcherWizard(const std::vector<sp<AtomMatchingTracker>>& eventTrackers) : mAllEventMatchers(eventTrackers){}; virtual ~EventMatcherWizard(){}; @@ -33,7 +33,7 @@ public: MatchingState matchLogEvent(const LogEvent& event, int matcher_index); private: - std::vector<sp<LogMatchingTracker>> mAllEventMatchers; + std::vector<sp<AtomMatchingTracker>> mAllEventMatchers; }; } // namespace statsd diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h deleted file mode 100644 index 88ab4e6f683a..000000000000 --- a/cmds/statsd/src/matchers/LogMatchingTracker.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LOG_MATCHING_TRACKER_H -#define LOG_MATCHING_TRACKER_H - -#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" -#include "logd/LogEvent.h" -#include "matchers/matcher_util.h" - -#include <utils/RefBase.h> - -#include <set> -#include <unordered_map> -#include <vector> - -namespace android { -namespace os { -namespace statsd { - -class LogMatchingTracker : public virtual RefBase { -public: - LogMatchingTracker(const int64_t& id, const int index) - : mId(id), mIndex(index), mInitialized(false){}; - - virtual ~LogMatchingTracker(){}; - - // Initialize this LogMatchingTracker. - // allLogMatchers: the list of the AtomMatcher proto config. This is needed because we don't - // store the proto object in memory. We only need it during initilization. - // allTrackers: the list of the LogMatchingTracker objects. It's a one-to-one mapping with - // allLogMatchers. This is needed because the initialization is done recursively - // for CombinationLogMatchingTrackers using DFS. - // stack: a bit map to record which matcher has been visited on the stack. This is for detecting - // circle dependency. - virtual bool init(const std::vector<AtomMatcher>& allLogMatchers, - const std::vector<sp<LogMatchingTracker>>& allTrackers, - const std::unordered_map<int64_t, int>& matcherMap, - std::vector<bool>& stack) = 0; - - // Called when a log event comes. - // event: the log event. - // allTrackers: the list of all LogMatchingTrackers. This is needed because the log processing - // is done recursively. - // matcherResults: The cached results for all matchers for this event. Parent matchers can - // directly access the children's matching results if they have been evaluated. - // Otherwise, call children matchers' onLogEvent. - virtual void onLogEvent(const LogEvent& event, - const std::vector<sp<LogMatchingTracker>>& allTrackers, - std::vector<MatchingState>& matcherResults) = 0; - - // Get the tagIds that this matcher cares about. The combined collection is stored - // in MetricMananger, so that we can pass any LogEvents that are not interest of us. It uses - // some memory but hopefully it can save us much CPU time when there is flood of events. - virtual const std::set<int>& getAtomIds() const { - return mAtomIds; - } - - const int64_t& getId() const { - return mId; - } - -protected: - // Name of this matching. We don't really need the name, but it makes log message easy to debug. - const int64_t mId; - - // Index of this LogMatchingTracker in MetricsManager's container. - const int mIndex; - - // Whether this LogMatchingTracker has been properly initialized. - bool mInitialized; - - // The collection of the event tag ids that this LogMatchingTracker cares. So we can quickly - // return kNotMatched when we receive an event with an id not in the list. This is especially - // useful when we have a complex CombinationLogMatcherTracker. - std::set<int> mAtomIds; -}; - -} // namespace statsd -} // namespace os -} // namespace android - -#endif // LOG_MATCHING_TRACKER_H diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp index 082daf5a1916..423da5bd3cf8 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp @@ -17,7 +17,7 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include "SimpleLogMatchingTracker.h" +#include "SimpleAtomMatchingTracker.h" namespace android { namespace os { @@ -26,11 +26,11 @@ namespace statsd { using std::unordered_map; using std::vector; - -SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int index, - const SimpleAtomMatcher& matcher, - const UidMap& uidMap) - : LogMatchingTracker(id, index), mMatcher(matcher), mUidMap(uidMap) { +SimpleAtomMatchingTracker::SimpleAtomMatchingTracker(const int64_t& id, const int index, + const uint64_t protoHash, + const SimpleAtomMatcher& matcher, + const sp<UidMap>& uidMap) + : AtomMatchingTracker(id, index, protoHash), mMatcher(matcher), mUidMap(uidMap) { if (!matcher.has_atom_id()) { mInitialized = false; } else { @@ -39,20 +39,28 @@ SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int } } -SimpleLogMatchingTracker::~SimpleLogMatchingTracker() { +SimpleAtomMatchingTracker::~SimpleAtomMatchingTracker() { } -bool SimpleLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers, - const vector<sp<LogMatchingTracker>>& allTrackers, - const unordered_map<int64_t, int>& matcherMap, - vector<bool>& stack) { +bool SimpleAtomMatchingTracker::init(const vector<AtomMatcher>& allAtomMatchers, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& matcherMap, + vector<bool>& stack) { // no need to do anything. return mInitialized; } -void SimpleLogMatchingTracker::onLogEvent(const LogEvent& event, - const vector<sp<LogMatchingTracker>>& allTrackers, - vector<MatchingState>& matcherResults) { +bool SimpleAtomMatchingTracker::onConfigUpdated( + const AtomMatcher& matcher, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + mIndex = index; + // Do not need to update mMatcher since the matcher must be identical across the update. + return mInitialized; +} + +void SimpleAtomMatchingTracker::onLogEvent( + const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + vector<MatchingState>& matcherResults) { if (matcherResults[mIndex] != MatchingState::kNotComputed) { VLOG("Matcher %lld already evaluated ", (long long)mId); return; @@ -65,7 +73,7 @@ void SimpleLogMatchingTracker::onLogEvent(const LogEvent& event, bool matched = matchesSimple(mUidMap, mMatcher, event); matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched; - VLOG("Stats SimpleLogMatcher %lld matched? %d", (long long)mId, matched); + VLOG("Stats SimpleAtomMatcher %lld matched? %d", (long long)mId, matched); } } // namespace statsd diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h index a0f6a888bd44..b67e6c20e8f1 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef SIMPLE_LOG_MATCHING_TRACKER_H -#define SIMPLE_LOG_MATCHING_TRACKER_H +#ifndef SIMPLE_ATOM_MATCHING_TRACKER_H +#define SIMPLE_ATOM_MATCHING_TRACKER_H #include <unordered_map> #include <vector> -#include "LogMatchingTracker.h" + +#include "AtomMatchingTracker.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "packages/UidMap.h" @@ -27,29 +28,31 @@ namespace android { namespace os { namespace statsd { -class SimpleLogMatchingTracker : public virtual LogMatchingTracker { +class SimpleAtomMatchingTracker : public AtomMatchingTracker { public: - SimpleLogMatchingTracker(const int64_t& id, const int index, - const SimpleAtomMatcher& matcher, - const UidMap& uidMap); + SimpleAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash, + const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap); - ~SimpleLogMatchingTracker(); + ~SimpleAtomMatchingTracker(); - bool init(const std::vector<AtomMatcher>& allLogMatchers, - const std::vector<sp<LogMatchingTracker>>& allTrackers, + bool init(const std::vector<AtomMatcher>& allAtomMatchers, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, const std::unordered_map<int64_t, int>& matcherMap, std::vector<bool>& stack) override; + bool onConfigUpdated(const AtomMatcher& matcher, const int index, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override; + void onLogEvent(const LogEvent& event, - const std::vector<sp<LogMatchingTracker>>& allTrackers, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, std::vector<MatchingState>& matcherResults) override; private: const SimpleAtomMatcher mMatcher; - const UidMap& mUidMap; + const sp<UidMap> mUidMap; }; } // namespace statsd } // namespace os } // namespace android -#endif // SIMPLE_LOG_MATCHING_TRACKER_H +#endif // SIMPLE_ATOM_MATCHING_TRACKER_H diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 2b4c6a3cbf1e..a7454c5d923b 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -17,7 +17,7 @@ #include "Log.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" -#include "matchers/LogMatchingTracker.h" +#include "matchers/AtomMatchingTracker.h" #include "matchers/matcher_util.h" #include "stats_util.h" @@ -81,14 +81,15 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera return matched; } -bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const string& str_match) { +bool tryMatchString(const sp<UidMap>& uidMap, const FieldValue& fieldValue, + const string& str_match) { if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) { int uid = fieldValue.mValue.int_value; auto aidIt = UidMap::sAidToUidMapping.find(str_match); if (aidIt != UidMap::sAidToUidMapping.end()) { return ((int)aidIt->second) == uid; } - std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/); + std::set<string> packageNames = uidMap->getAppNamesFromUid(uid, true /* normalize*/); return packageNames.find(str_match) != packageNames.end(); } else if (fieldValue.mValue.getType() == STRING) { return fieldValue.mValue.str_value == str_match; @@ -96,7 +97,7 @@ bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const st return false; } -bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, +bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher, const vector<FieldValue>& values, int start, int end, int depth) { if (depth > 2) { ALOGE("Depth > 3 not supported"); @@ -353,7 +354,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } -bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher, +bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher, const LogEvent& event) { if (event.GetTagId() != simpleMatcher.atom_id()) { return false; diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h index 1ab3e87b5fed..130b6068bd19 100644 --- a/cmds/statsd/src/matchers/matcher_util.h +++ b/cmds/statsd/src/matchers/matcher_util.h @@ -36,8 +36,8 @@ enum MatchingState { bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation, const std::vector<MatchingState>& matcherResults); -bool matchesSimple(const UidMap& uidMap, - const SimpleAtomMatcher& simpleMatcher, const LogEvent& wrapper); +bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher, + const LogEvent& wrapper); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 573961276e5b..3dbb6ed47ff8 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -69,13 +69,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6; CountMetricProducer::CountMetricProducer( const ConfigKey& key, const CountMetric& metric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, - const int64_t timeBaseNs, const int64_t startTimeNs, + const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap, const vector<int>& slicedStateAtoms, const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard, - eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) { + protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms, + stateGroupMap) { if (metric.has_bucket()) { mBucketSizeNs = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000; diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index f05fb061ccc1..6b2f2ca61ecc 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -44,7 +44,7 @@ public: CountMetricProducer( const ConfigKey& key, const CountMetric& countMetric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, - const int64_t timeBaseNs, const int64_t startTimeNs, + const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {}, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& eventDeactivationMap = {}, @@ -57,6 +57,10 @@ public: const HashableDimensionKey& primaryKey, const FieldValue& oldState, const FieldValue& newState) override; + MetricType getMetricType() const override { + return METRIC_TYPE_COUNT; + } + protected: void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index e9b043876d3d..3acafaa3560e 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -66,14 +66,15 @@ DurationMetricProducer::DurationMetricProducer( const ConfigKey& key, const DurationMetric& metric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex, const bool nesting, - const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions, - const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<ConditionWizard>& wizard, const uint64_t protoHash, + const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap, const vector<int>& slicedStateAtoms, const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard, - eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap), + protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms, + stateGroupMap), mAggregationType(metric.aggregation_type()), mStartIndex(startIndex), mStopIndex(stopIndex), diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index bfe1010c89de..3a94d9c775aa 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -42,8 +42,9 @@ public: const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex, const bool nesting, - const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions, - const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<ConditionWizard>& wizard, const uint64_t protoHash, + const FieldMatcher& internalDimensions, const int64_t timeBaseNs, + const int64_t startTimeNs, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap = {}, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap = {}, const vector<int>& slicedStateAtoms = {}, @@ -58,6 +59,10 @@ public: const HashableDimensionKey& primaryKey, const FieldValue& oldState, const FieldValue& newState) override; + MetricType getMetricType() const override { + return METRIC_TYPE_DURATION; + } + protected: void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index dc0036a687f3..dfe4559b05fb 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -55,13 +55,14 @@ const int FIELD_ID_ATOMS = 2; EventMetricProducer::EventMetricProducer( const ConfigKey& key, const EventMetric& metric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, - const int64_t startTimeNs, + const uint64_t protoHash, const int64_t startTimeNs, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap, const vector<int>& slicedStateAtoms, const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard, - eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) { + protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms, + stateGroupMap) { if (metric.links().size() > 0) { for (const auto& link : metric.links()) { Metric2Condition mc; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index bfb2de36fad4..e828dddcbb18 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -36,7 +36,7 @@ public: EventMetricProducer( const ConfigKey& key, const EventMetric& eventMetric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, - const int64_t startTimeNs, + const uint64_t protoHash, const int64_t startTimeNs, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {}, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& eventDeactivationMap = {}, @@ -45,6 +45,10 @@ public: virtual ~EventMetricProducer(); + MetricType getMetricType() const override { + return METRIC_TYPE_EVENT; + } + private: void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 020f4b638f4d..9dda248a6d1f 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -71,13 +71,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8; GaugeMetricProducer::GaugeMetricProducer( const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, - const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard, - const int pullTagId, const int triggerAtomId, const int atomId, const int64_t timeBaseNs, - const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager, + const uint64_t protoHash, const int whatMatcherIndex, + const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId, + const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<StatsPullerManager>& pullerManager, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard, - eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{}, + protoHash, eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{}, /*stateGroupMap=*/{}), mWhatMatcherIndex(whatMatcherIndex), mEventMatcherWizard(matcherWizard), diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index 2fc772b6b641..e933d4b19716 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -59,10 +59,11 @@ public: GaugeMetricProducer( const ConfigKey& key, const GaugeMetric& gaugeMetric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, - const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex, - const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, - const int triggerAtomId, const int atomId, const int64_t timeBaseNs, - const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager, + const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash, + const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard, + const int pullTagId, const int triggerAtomId, const int atomId, + const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<StatsPullerManager>& pullerManager, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {}, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& eventDeactivationMap = {}); @@ -96,6 +97,10 @@ public: } }; + MetricType getMetricType() const override { + return METRIC_TYPE_GAUGE; + } + protected: void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, @@ -170,14 +175,14 @@ private: // for each slice with the latest value. void updateCurrentSlicedBucketForAnomaly(); - // Whitelist of fields to report. Empty means all are reported. + // Allowlist of fields to report. Empty means all are reported. std::vector<Matcher> mFieldMatchers; GaugeMetric::SamplingType mSamplingType; const int64_t mMaxPullDelayNs; - // apply a whitelist on the original input + // apply an allowlist on the original input std::shared_ptr<vector<FieldValue>> getGaugeFields(const LogEvent& event); // Util function to check whether the specified dimension hits the guardrail. diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index fe143e496373..c1c1d20f00e2 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -46,13 +46,14 @@ const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3; MetricProducer::MetricProducer( const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs, const int conditionIndex, const vector<ConditionState>& initialConditionCache, - const sp<ConditionWizard>& wizard, + const sp<ConditionWizard>& wizard, const uint64_t protoHash, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& eventDeactivationMap, const vector<int>& slicedStateAtoms, const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) : mMetricId(metricId), + mProtoHash(protoHash), mConfigKey(key), mTimeBaseNs(timeBaseNs), mCurrentBucketStartTimeNs(timeBaseNs), diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index be4cd6724bb1..bb590aac54d6 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -87,6 +87,13 @@ enum BucketDropReason { NO_DATA = 9 }; +enum MetricType { + METRIC_TYPE_EVENT = 1, + METRIC_TYPE_COUNT = 2, + METRIC_TYPE_DURATION = 3, + METRIC_TYPE_GAUGE = 4, + METRIC_TYPE_VALUE = 5, +}; struct Activation { Activation(const ActivationType& activationType, const int64_t ttlNs) : ttl_ns(ttlNs), @@ -130,7 +137,7 @@ class MetricProducer : public virtual android::RefBase, public virtual StateList public: MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs, const int conditionIndex, const vector<ConditionState>& initialConditionCache, - const sp<ConditionWizard>& wizard, + const sp<ConditionWizard>& wizard, const uint64_t protoHash, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& eventDeactivationMap, @@ -259,10 +266,16 @@ public: int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto); // Start: getters/setters - inline const int64_t& getMetricId() const { + inline int64_t getMetricId() const { return mMetricId; } + inline uint64_t getProtoHash() const { + return mProtoHash; + } + + virtual MetricType getMetricType() const = 0; + // For test only. inline int64_t getCurrentBucketNum() const { return mCurrentBucketNum; @@ -400,6 +413,10 @@ protected: const int64_t mMetricId; + // Hash of the Metric's proto bytes from StatsdConfig, including any activations. + // Used to determine if the definition of this metric has changed across a config update. + const uint64_t mProtoHash; + const ConfigKey mConfigKey; // The time when this metric producer was first created. The end time for the current bucket diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 60de1a24cce5..39806890c42d 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -24,9 +24,10 @@ #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" #include "guardrail/StatsdStats.h" -#include "matchers/CombinationLogMatchingTracker.h" -#include "matchers/SimpleLogMatchingTracker.h" -#include "metrics_manager_util.h" +#include "matchers/CombinationAtomMatchingTracker.h" +#include "matchers/SimpleAtomMatchingTracker.h" +#include "parsing_utils/config_update_utils.h" +#include "parsing_utils/metrics_manager_util.h" #include "state/StateManager.h" #include "stats_log_util.h" #include "stats_util.h" @@ -77,12 +78,13 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, refreshTtl(timeBaseNs); mConfigValid = initStatsdConfig( - key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers, - mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, - mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, - mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap, - mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds); + key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, + mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap, + mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap, + mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap, + mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation, + mStateProtoHashes, mNoReportMetricIds); mHashStringsInReport = config.hash_strings_in_metric_report(); mVersionStringsInReport = config.version_strings_in_metric_report(); @@ -91,7 +93,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, // Init allowed pushed atom uids. if (config.allowed_log_source_size() == 0) { mConfigValid = false; - ALOGE("Log source whitelist is empty! This config won't get any data. Suggest adding at " + ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at " "least AID_SYSTEM and AID_STATSD to the allowed_log_source field."); } else { for (const auto& source : config.allowed_log_source()) { @@ -153,7 +155,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, // Guardrail. Reject the config if it's too big. if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig || mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig || - mAllAtomMatchers.size() > StatsdStats::kMaxMatcherCountPerConfig) { + mAllAtomMatchingTrackers.size() > StatsdStats::kMaxMatcherCountPerConfig) { ALOGE("This config is too big! Reject!"); mConfigValid = false; } @@ -173,8 +175,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, // no matter whether this config is valid, log it in the stats. StatsdStats::getInstance().noteConfigReceived( - key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(), - mAllAnomalyTrackers.size(), mAnnotations, mConfigValid); + key, mAllMetricProducers.size(), mAllConditionTrackers.size(), + mAllAtomMatchingTrackers.size(), mAllAnomalyTrackers.size(), mAnnotations, + mConfigValid); // Check active for (const auto& metric : mAllMetricProducers) { if (metric->isActive()) { @@ -195,6 +198,29 @@ MetricsManager::~MetricsManager() { VLOG("~MetricsManager()"); } +bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor) { + vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers; + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + vector<sp<ConditionTracker>> newConditionTrackers; + unordered_map<int64_t, int> newConditionTrackerMap; + mTagIds.clear(); + mTrackerToConditionMap.clear(); + mConfigValid = updateStatsdConfig( + mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, + mAllConditionTrackers, mConditionTrackerMap, mTagIds, newAtomMatchingTrackers, + newAtomMatchingTrackerMap, newConditionTrackers, newConditionTrackerMap, + mTrackerToConditionMap); + mAllAtomMatchingTrackers = newAtomMatchingTrackers; + mAtomMatchingTrackerMap = newAtomMatchingTrackerMap; + mAllConditionTrackers = newConditionTrackers; + mConditionTrackerMap = newConditionTrackerMap; + return mConfigValid; +} + void MetricsManager::initLogSourceWhiteList() { std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex); mAllowedLogSources.clear(); @@ -484,11 +510,12 @@ void MetricsManager::onLogEvent(const LogEvent& event) { return; } - vector<MatchingState> matcherCache(mAllAtomMatchers.size(), MatchingState::kNotComputed); + vector<MatchingState> matcherCache(mAllAtomMatchingTrackers.size(), + MatchingState::kNotComputed); // Evaluate all atom matchers. - for (auto& matcher : mAllAtomMatchers) { - matcher->onLogEvent(event, mAllAtomMatchers, matcherCache); + for (auto& matcher : mAllAtomMatchingTrackers) { + matcher->onLogEvent(event, mAllAtomMatchingTrackers, matcherCache); } // Set of metrics that received an activation cancellation. @@ -578,10 +605,10 @@ void MetricsManager::onLogEvent(const LogEvent& event) { } // For matched AtomMatchers, tell relevant metrics that a matched event has come. - for (size_t i = 0; i < mAllAtomMatchers.size(); i++) { + for (size_t i = 0; i < mAllAtomMatchingTrackers.size(); i++) { if (matcherCache[i] == MatchingState::kMatched) { StatsdStats::getInstance().noteMatcherMatched(mConfigKey, - mAllAtomMatchers[i]->getId()); + mAllAtomMatchingTrackers[i]->getId()); auto pair = mTrackerToMetricMap.find(i); if (pair != mTrackerToMetricMap.end()) { auto& metricList = pair->second; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index ad30a88c5d19..27f3d51b07ce 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -25,7 +25,7 @@ #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h" #include "logd/LogEvent.h" -#include "matchers/LogMatchingTracker.h" +#include "matchers/AtomMatchingTracker.h" #include "metrics/MetricProducer.h" #include "packages/UidMap.h" @@ -46,6 +46,10 @@ public: virtual ~MetricsManager(); + bool updateConfig(const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor); + // Return whether the configuration is valid. bool isConfigValid() const; @@ -213,7 +217,7 @@ private: // All event tags that are interesting to my metrics. std::set<int> mTagIds; - // We only store the sp of LogMatchingTracker, MetricProducer, and ConditionTracker in + // We only store the sp of AtomMatchingTracker, MetricProducer, and ConditionTracker in // MetricsManager. There are relationships between them, and the relationships are denoted by // index instead of pointers. The reasons for this are: (1) the relationship between them are // complicated, so storing index instead of pointers reduces the risk that A holds B's sp, and B @@ -221,7 +225,7 @@ private: // the related results from a cache using the index. // Hold all the atom matchers from the config. - std::vector<sp<LogMatchingTracker>> mAllAtomMatchers; + std::vector<sp<AtomMatchingTracker>> mAllAtomMatchingTrackers; // Hold all the conditions from the config. std::vector<sp<ConditionTracker>> mAllConditionTrackers; @@ -235,23 +239,35 @@ private: // Hold all periodic alarm trackers. std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers; + // To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and + // ConditionTracker to its index in the corresponding vector. + + // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers. + std::unordered_map<int64_t, int> mAtomMatchingTrackerMap; + + // Maps the id of a condition tracker to its index in mAllConditionTrackers. + std::unordered_map<int64_t, int> mConditionTrackerMap; + + // Maps the id of a metric producer to its index in mAllMetricProducers. + std::unordered_map<int64_t, int> mMetricProducerMap; + // To make the log processing more efficient, we want to do as much filtering as possible // before we go into individual trackers and conditions to match. // 1st filter: check if the event tag id is in mTagIds. // 2nd filter: if it is, we parse the event because there is at least one member is interested. - // then pass to all LogMatchingTrackers (itself also filter events by ids). - // 3nd filter: for LogMatchingTrackers that matched this event, we pass this event to the + // then pass to all AtomMatchingTrackers (itself also filter events by ids). + // 3nd filter: for AtomMatchingTrackers that matched this event, we pass this event to the // ConditionTrackers and MetricProducers that use this matcher. // 4th filter: for ConditionTrackers that changed value due to this event, we pass // new conditions to metrics that use this condition. // The following map is initialized from the statsd_config. - // Maps from the index of the LogMatchingTracker to index of MetricProducer. + // Maps from the index of the AtomMatchingTracker to index of MetricProducer. std::unordered_map<int, std::vector<int>> mTrackerToMetricMap; - // Maps from LogMatchingTracker to ConditionTracker + // Maps from AtomMatchingTracker to ConditionTracker std::unordered_map<int, std::vector<int>> mTrackerToConditionMap; // Maps from ConditionTracker to MetricProducer @@ -282,6 +298,9 @@ private: // The config is always active if any metric in the config does not have an activation signal. bool mIsAlwaysActive; + // Hashes of the States used in this config, keyed by the state id, used in config updates. + std::map<int64_t, uint64_t> mStateProtoHashes; + FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 5987a723a421..39ae9a47f2bf 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -79,16 +79,17 @@ const Value ZERO_DOUBLE((int64_t)0); ValueMetricProducer::ValueMetricProducer( const ConfigKey& key, const ValueMetric& metric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, - const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex, - const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs, - const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager, + const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash, + const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard, + const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<StatsPullerManager>& pullerManager, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap, const vector<int>& slicedStateAtoms, const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, - conditionWizard, eventActivationMap, eventDeactivationMap, slicedStateAtoms, - stateGroupMap), + conditionWizard, protoHash, eventActivationMap, eventDeactivationMap, + slicedStateAtoms, stateGroupMap), mWhatMatcherIndex(whatMatcherIndex), mEventMatcherWizard(matcherWizard), mPullerManager(pullerManager), @@ -411,7 +412,7 @@ void ValueMetricProducer::skipCurrentBucket(const int64_t dropTimeNs, void ValueMetricProducer::resetBase() { for (auto& slice : mCurrentBaseInfo) { - for (auto& baseInfo : slice.second) { + for (auto& baseInfo : slice.second.baseInfos) { baseInfo.hasBase = false; } } @@ -623,7 +624,7 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end(); if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) { auto it = mCurrentBaseInfo.find(whatKey); - for (auto& baseInfo : it->second) { + for (auto& baseInfo : it->second.baseInfos) { baseInfo.hasBase = false; } } @@ -652,7 +653,7 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { (unsigned long)mCurrentSlicedBucket.size()); if (verbose) { for (const auto& it : mCurrentSlicedBucket) { - for (const auto& interval : it.second) { + for (const auto& interval : it.second.intervals) { fprintf(out, "\t(what)%s\t(states)%s (value)%s\n", it.first.getDimensionKeyInWhat().toString().c_str(), it.first.getStateValuesKey().toString().c_str(), @@ -733,6 +734,11 @@ bool getDoubleOrLong(const LogEvent& event, const Matcher& matcher, Value& ret) return false; } +bool ValueMetricProducer::multipleBucketsSkipped(const int64_t numBucketsForward) { + // Skip buckets if this is a pulled metric or a pushed metric that is diffed. + return numBucketsForward > 1 && (mIsPulled || mUseDiff); +} + void ValueMetricProducer::onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, const ConditionKey& conditionKey, bool condition, const LogEvent& event, @@ -783,23 +789,23 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( return; } - vector<BaseInfo>& baseInfos = mCurrentBaseInfo[whatKey]; + DimensionsInWhatInfo& dimensionsInWhatInfo = mCurrentBaseInfo[whatKey]; + vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos; if (baseInfos.size() < mFieldMatchers.size()) { VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size()); baseInfos.resize(mFieldMatchers.size()); } - for (BaseInfo& baseInfo : baseInfos) { - if (!baseInfo.hasCurrentState) { - baseInfo.currentState = getUnknownStateKey(); - baseInfo.hasCurrentState = true; - } + if (!dimensionsInWhatInfo.hasCurrentState) { + dimensionsInWhatInfo.currentState = getUnknownStateKey(); + dimensionsInWhatInfo.hasCurrentState = true; } // We need to get the intervals stored with the previous state key so we can // close these value intervals. - const auto oldStateKey = baseInfos[0].currentState; - vector<Interval>& intervals = mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)]; + const auto oldStateKey = dimensionsInWhatInfo.currentState; + vector<Interval>& intervals = + mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals; if (intervals.size() < mFieldMatchers.size()) { VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size()); intervals.resize(mFieldMatchers.size()); @@ -813,14 +819,14 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( // Discussion here: http://ag/6124370. bool useAnomalyDetection = true; + dimensionsInWhatInfo.hasCurrentState = true; + dimensionsInWhatInfo.currentState = stateKey; for (int i = 0; i < (int)mFieldMatchers.size(); i++) { const Matcher& matcher = mFieldMatchers[i]; BaseInfo& baseInfo = baseInfos[i]; Interval& interval = intervals[i]; interval.valueIndex = i; Value value; - baseInfo.hasCurrentState = true; - baseInfo.currentState = stateKey; if (!getDoubleOrLong(event, matcher, value)) { VLOG("Failed to get value %d from event %s", i, event.ToString().c_str()); StatsdStats::getInstance().noteBadValueType(mMetricId); @@ -910,8 +916,9 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( interval.sampleSize += 1; } - // Only trigger the tracker if all intervals are correct - if (useAnomalyDetection) { + // Only trigger the tracker if all intervals are correct and we have not skipped the bucket due + // to MULTIPLE_BUCKETS_SKIPPED. + if (useAnomalyDetection && !multipleBucketsSkipped(calcBucketsForwardCount(eventTimeNs))) { // TODO: propgate proper values down stream when anomaly support doubles long wholeBucketVal = intervals[0].value.long_value; auto prev = mCurrentFullBucket.find(eventKey); @@ -961,9 +968,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, int64_t bucketEndTime = fullBucketEndTimeNs; int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs); - // Skip buckets if this is a pulled metric or a pushed metric that is diffed. - if (numBucketsForward > 1 && (mIsPulled || mUseDiff)) { - + if (multipleBucketsSkipped(numBucketsForward)) { VLOG("Skipping forward %lld buckets", (long long)numBucketsForward); StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId); // Something went wrong. Maybe the device was sleeping for a long time. It is better @@ -986,7 +991,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, bool bucketHasData = false; // The current bucket is large enough to keep. for (const auto& slice : mCurrentSlicedBucket) { - ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second); + PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals); bucket.mConditionTrueNs = conditionTrueDuration; // it will auto create new vector of ValuebucketInfo if the key is not found. if (bucket.valueIndex.size() > 0) { @@ -1026,9 +1031,9 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, mCurrentBucketNum += numBucketsForward; } -ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime, - const std::vector<Interval>& intervals) { - ValueBucket bucket; +PastValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime, + const std::vector<Interval>& intervals) { + PastValueBucket bucket; bucket.mBucketStartNs = mCurrentBucketStartTimeNs; bucket.mBucketEndNs = bucketEndTime; for (const auto& interval : intervals) { @@ -1055,7 +1060,7 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) // Cleanup data structure to aggregate values. for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) { bool obsolete = true; - for (auto& interval : it->second) { + for (auto& interval : it->second.intervals) { interval.hasValue = false; interval.sampleSize = 0; if (interval.seenNewData) { @@ -1103,7 +1108,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { continue; } // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { mCurrentFullBucket[slice.first] += interval.value.long_value; } @@ -1122,7 +1127,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { for (auto& tracker : mAnomalyTrackers) { if (tracker != nullptr) { // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { tracker->addPastBucket(slice.first, interval.value.long_value, mCurrentBucketNum); @@ -1135,7 +1140,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { // Accumulate partial bucket. for (const auto& slice : mCurrentSlicedBucket) { // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { mCurrentFullBucket[slice.first] += interval.value.long_value; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index b359af745c91..4b2599bdb517 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -31,7 +31,7 @@ namespace android { namespace os { namespace statsd { -struct ValueBucket { +struct PastValueBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; std::vector<int> valueIndex; @@ -41,7 +41,6 @@ struct ValueBucket { int64_t mConditionTrueNs; }; - // Aggregates values within buckets. // // There are different events that might complete a bucket @@ -53,9 +52,9 @@ public: ValueMetricProducer( const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex, const vector<ConditionState>& initialConditionCache, - const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex, - const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, - const int64_t timeBaseNs, const int64_t startTimeNs, + const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash, + const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard, + const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager, const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {}, const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& @@ -93,6 +92,10 @@ public: void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey, const FieldValue& oldState, const FieldValue& newState) override; + MetricType getMetricType() const override { + return METRIC_TYPE_VALUE; + } + protected: void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, @@ -173,7 +176,7 @@ private: // if this is pulled metric const bool mIsPulled; - // internal state of an ongoing aggregation bucket. + // Tracks the value information of one value field. typedef struct { // Index in multi value aggregation. int valueIndex; @@ -188,25 +191,40 @@ private: bool seenNewData = false; } Interval; + // Internal state of an ongoing aggregation bucket. + typedef struct CurrentValueBucket { + // Value information for each value field of the metric. + std::vector<Interval> intervals; + } CurrentValueBucket; + + // Holds base information for diffing values from one value field. typedef struct { // Holds current base value of the dimension. Take diff and update if necessary. Value base; // Whether there is a base to diff to. bool hasBase; + } BaseInfo; + + // State key and base information for a specific DimensionsInWhat key. + typedef struct { + std::vector<BaseInfo> baseInfos; // Last seen state value(s). HashableDimensionKey currentState; // Whether this dimensions in what key has a current state key. bool hasCurrentState; - } BaseInfo; + } DimensionsInWhatInfo; - std::unordered_map<MetricDimensionKey, std::vector<Interval>> mCurrentSlicedBucket; + // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat + // key and StateValuesKey pair. + std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket; - std::unordered_map<HashableDimensionKey, std::vector<BaseInfo>> mCurrentBaseInfo; + // Tracks current state key and base information for each DimensionsInWhat key. + std::unordered_map<HashableDimensionKey, DimensionsInWhatInfo> mCurrentBaseInfo; std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket; // Save the past buckets and we can clear when the StatsLogReport is dumped. - std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets; + std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets; const int64_t mMinBucketSizeNs; @@ -219,11 +237,13 @@ private: void pullAndMatchEventsLocked(const int64_t timestampNs); + bool multipleBucketsSkipped(const int64_t numBucketsForward); + void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, int64_t originalPullTimeNs, int64_t eventElapsedTimeNs); - ValueBucket buildPartialBucket(int64_t bucketEndTime, - const std::vector<Interval>& intervals); + PastValueBucket buildPartialBucket(int64_t bucketEndTime, + const std::vector<Interval>& intervals); void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs); @@ -232,7 +252,7 @@ private: // Reset diff base and mHasGlobalBase void resetBase(); - static const size_t kBucketSize = sizeof(ValueBucket{}); + static const size_t kBucketSize = sizeof(PastValueBucket{}); const size_t mDimensionSoftLimit; diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp new file mode 100644 index 000000000000..bd60b6bfcb8e --- /dev/null +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -0,0 +1,438 @@ +/* + * 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. + */ + +#define DEBUG false // STOPSHIP if true +#include "Log.h" + +#include "config_update_utils.h" + +#include "external/StatsPullerManager.h" +#include "hash.h" +#include "metrics_manager_util.h" + +namespace android { +namespace os { +namespace statsd { + +// Recursive function to determine if a matcher needs to be updated. Populates matcherToUpdate. +// Returns whether the function was successful or not. +bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx, + const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + vector<UpdateStatus>& matchersToUpdate, + vector<bool>& cycleTracker) { + // Have already examined this matcher. + if (matchersToUpdate[matcherIdx] != UPDATE_UNKNOWN) { + return true; + } + + const AtomMatcher& matcher = config.atom_matcher(matcherIdx); + int64_t id = matcher.id(); + // Check if new matcher. + const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id); + if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) { + matchersToUpdate[matcherIdx] = UPDATE_NEW; + return true; + } + + // This is an existing matcher. Check if it has changed. + string serializedMatcher; + if (!matcher.SerializeToString(&serializedMatcher)) { + ALOGE("Unable to serialize matcher %lld", (long long)id); + return false; + } + uint64_t newProtoHash = Hash64(serializedMatcher); + if (newProtoHash != oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second]->getProtoHash()) { + matchersToUpdate[matcherIdx] = UPDATE_REPLACE; + return true; + } + + switch (matcher.contents_case()) { + case AtomMatcher::ContentsCase::kSimpleAtomMatcher: { + matchersToUpdate[matcherIdx] = UPDATE_PRESERVE; + return true; + } + case AtomMatcher::ContentsCase::kCombination: { + // Recurse to check if children have changed. + cycleTracker[matcherIdx] = true; + UpdateStatus status = UPDATE_PRESERVE; + for (const int64_t childMatcherId : matcher.combination().matcher()) { + const auto& childIt = newAtomMatchingTrackerMap.find(childMatcherId); + if (childIt == newAtomMatchingTrackerMap.end()) { + ALOGW("Matcher %lld not found in the config", (long long)childMatcherId); + return false; + } + const int childIdx = childIt->second; + if (cycleTracker[childIdx]) { + ALOGE("Cycle detected in matcher config"); + return false; + } + if (!determineMatcherUpdateStatus( + config, childIdx, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, + newAtomMatchingTrackerMap, matchersToUpdate, cycleTracker)) { + return false; + } + + if (matchersToUpdate[childIdx] == UPDATE_REPLACE) { + status = UPDATE_REPLACE; + break; + } + } + matchersToUpdate[matcherIdx] = status; + cycleTracker[matcherIdx] = false; + return true; + } + default: { + ALOGE("Matcher \"%lld\" malformed", (long long)id); + return false; + } + } + return true; +} + +bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + set<int>& allTagIds, + unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + set<int64_t>& replacedMatchers) { + const int atomMatcherCount = config.atom_matcher_size(); + + vector<AtomMatcher> matcherProtos; + matcherProtos.reserve(atomMatcherCount); + newAtomMatchingTrackers.reserve(atomMatcherCount); + + // Maps matcher id to their position in the config. For fast lookup of dependencies. + for (int i = 0; i < atomMatcherCount; i++) { + const AtomMatcher& matcher = config.atom_matcher(i); + if (newAtomMatchingTrackerMap.find(matcher.id()) != newAtomMatchingTrackerMap.end()) { + ALOGE("Duplicate atom matcher found for id %lld", (long long)matcher.id()); + return false; + } + newAtomMatchingTrackerMap[matcher.id()] = i; + matcherProtos.push_back(matcher); + } + + // For combination matchers, we need to determine if any children need to be updated. + vector<UpdateStatus> matchersToUpdate(atomMatcherCount, UPDATE_UNKNOWN); + vector<bool> cycleTracker(atomMatcherCount, false); + for (int i = 0; i < atomMatcherCount; i++) { + if (!determineMatcherUpdateStatus(config, i, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)) { + return false; + } + } + + for (int i = 0; i < atomMatcherCount; i++) { + const AtomMatcher& matcher = config.atom_matcher(i); + const int64_t id = matcher.id(); + switch (matchersToUpdate[i]) { + case UPDATE_PRESERVE: { + const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id); + if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) { + ALOGE("Could not find AtomMatcher %lld in the previous config, but expected it " + "to be there", + (long long)id); + return false; + } + const sp<AtomMatchingTracker>& tracker = + oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second]; + if (!tracker->onConfigUpdated(matcherProtos[i], i, newAtomMatchingTrackerMap)) { + ALOGW("Config update failed for matcher %lld", (long long)id); + return false; + } + newAtomMatchingTrackers.push_back(tracker); + break; + } + case UPDATE_REPLACE: + replacedMatchers.insert(id); + [[fallthrough]]; // Intentionally fallthrough to create the new matcher. + case UPDATE_NEW: { + sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap); + if (tracker == nullptr) { + return false; + } + newAtomMatchingTrackers.push_back(tracker); + break; + } + default: { + ALOGE("Matcher \"%lld\" update state is unknown. This should never happen", + (long long)id); + return false; + } + } + } + + std::fill(cycleTracker.begin(), cycleTracker.end(), false); + for (auto& matcher : newAtomMatchingTrackers) { + if (!matcher->init(matcherProtos, newAtomMatchingTrackers, newAtomMatchingTrackerMap, + cycleTracker)) { + return false; + } + // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only. + const set<int>& tagIds = matcher->getAtomIds(); + allTagIds.insert(tagIds.begin(), tagIds.end()); + } + + return true; +} + +// Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate. +// Returns whether the function was successful or not. +bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx, + const unordered_map<int64_t, int>& oldConditionTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + const unordered_map<int64_t, int>& newConditionTrackerMap, + const set<int64_t>& replacedMatchers, + vector<UpdateStatus>& conditionsToUpdate, + vector<bool>& cycleTracker) { + // Have already examined this condition. + if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) { + return true; + } + + const Predicate& predicate = config.predicate(conditionIdx); + int64_t id = predicate.id(); + // Check if new condition. + const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); + if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_NEW; + return true; + } + + // This is an existing condition. Check if it has changed. + string serializedCondition; + if (!predicate.SerializeToString(&serializedCondition)) { + ALOGE("Unable to serialize matcher %lld", (long long)id); + return false; + } + uint64_t newProtoHash = Hash64(serializedCondition); + if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + + switch (predicate.contents_case()) { + case Predicate::ContentsCase::kSimplePredicate: { + // Need to check if any of the underlying matchers changed. + const SimplePredicate& simplePredicate = predicate.simple_predicate(); + if (simplePredicate.has_start()) { + if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + if (simplePredicate.has_stop()) { + if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + if (simplePredicate.has_stop_all()) { + if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE; + return true; + } + case Predicate::ContentsCase::kCombination: { + // Need to recurse on the children to see if any of the child predicates changed. + cycleTracker[conditionIdx] = true; + UpdateStatus status = UPDATE_PRESERVE; + for (const int64_t childPredicateId : predicate.combination().predicate()) { + const auto& childIt = newConditionTrackerMap.find(childPredicateId); + if (childIt == newConditionTrackerMap.end()) { + ALOGW("Predicate %lld not found in the config", (long long)childPredicateId); + return false; + } + const int childIdx = childIt->second; + if (cycleTracker[childIdx]) { + ALOGE("Cycle detected in predicate config"); + return false; + } + if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, + cycleTracker)) { + return false; + } + + if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) { + status = UPDATE_REPLACE; + break; + } + } + conditionsToUpdate[conditionIdx] = status; + cycleTracker[conditionIdx] = false; + return true; + } + default: { + ALOGE("Predicate \"%lld\" malformed", (long long)id); + return false; + } + } + + return true; +} + +bool updateConditions(const ConfigKey& key, const StatsdConfig& config, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const set<int64_t>& replacedMatchers, + const unordered_map<int64_t, int>& oldConditionTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + unordered_map<int64_t, int>& newConditionTrackerMap, + vector<sp<ConditionTracker>>& newConditionTrackers, + unordered_map<int, vector<int>>& trackerToConditionMap, + vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) { + vector<Predicate> conditionProtos; + const int conditionTrackerCount = config.predicate_size(); + conditionProtos.reserve(conditionTrackerCount); + newConditionTrackers.reserve(conditionTrackerCount); + conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated); + + for (int i = 0; i < conditionTrackerCount; i++) { + const Predicate& condition = config.predicate(i); + if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) { + ALOGE("Duplicate Predicate found!"); + return false; + } + newConditionTrackerMap[condition.id()] = i; + conditionProtos.push_back(condition); + } + + vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN); + vector<bool> cycleTracker(conditionTrackerCount, false); + for (int i = 0; i < conditionTrackerCount; i++) { + if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers, + newConditionTrackerMap, replacedMatchers, + conditionsToUpdate, cycleTracker)) { + return false; + } + } + + // Update status has been determined for all conditions. Now perform the update. + set<int> preservedConditions; + for (int i = 0; i < conditionTrackerCount; i++) { + const Predicate& predicate = config.predicate(i); + const int64_t id = predicate.id(); + switch (conditionsToUpdate[i]) { + case UPDATE_PRESERVE: { + preservedConditions.insert(i); + const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); + if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { + ALOGE("Could not find Predicate %lld in the previous config, but expected it " + "to be there", + (long long)id); + return false; + } + const int oldIndex = oldConditionTrackerIt->second; + newConditionTrackers.push_back(oldConditionTrackers[oldIndex]); + break; + } + case UPDATE_REPLACE: + replacedConditions.insert(id); + [[fallthrough]]; // Intentionally fallthrough to create the new condition tracker. + case UPDATE_NEW: { + sp<ConditionTracker> tracker = + createConditionTracker(key, predicate, i, atomMatchingTrackerMap); + if (tracker == nullptr) { + return false; + } + newConditionTrackers.push_back(tracker); + break; + } + default: { + ALOGE("Condition \"%lld\" update state is unknown. This should never happen", + (long long)id); + return false; + } + } + } + + // Update indices of preserved predicates. + for (const int conditionIndex : preservedConditions) { + if (!newConditionTrackers[conditionIndex]->onConfigUpdated( + conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap, + newConditionTrackerMap)) { + ALOGE("Failed to update condition %lld", + (long long)newConditionTrackers[conditionIndex]->getConditionId()); + return false; + } + } + + std::fill(cycleTracker.begin(), cycleTracker.end(), false); + for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) { + const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex]; + // Calling init on preserved conditions is OK. It is needed to fill the condition cache. + if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap, + cycleTracker, conditionCache)) { + return false; + } + for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) { + vector<int>& conditionList = trackerToConditionMap[trackerIndex]; + conditionList.push_back(conditionIndex); + } + } + return true; +} + +bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, + const sp<StatsPullerManager>& pullerManager, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + const unordered_map<int64_t, int>& oldConditionTrackerMap, + set<int>& allTagIds, + vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + vector<sp<ConditionTracker>>& newConditionTrackers, + unordered_map<int64_t, int>& newConditionTrackerMap, + unordered_map<int, vector<int>>& trackerToConditionMap) { + set<int64_t> replacedMatchers; + set<int64_t> replacedConditions; + vector<ConditionState> conditionCache; + + if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap, + newAtomMatchingTrackers, replacedMatchers)) { + ALOGE("updateAtomMatchingTrackers failed"); + return false; + } + VLOG("updateAtomMatchingTrackers succeeded"); + + if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers, + oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap, + newConditionTrackers, trackerToConditionMap, conditionCache, + replacedConditions)) { + ALOGE("updateConditions failed"); + return false; + } + VLOG("updateConditions succeeded"); + + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h new file mode 100644 index 000000000000..7ba684a65e88 --- /dev/null +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#pragma once + +#include <vector> + +#include "anomaly/AlarmMonitor.h" +#include "condition/ConditionTracker.h" +#include "external/StatsPullerManager.h" +#include "matchers/AtomMatchingTracker.h" + +namespace android { +namespace os { +namespace statsd { + +// Helper functions for MetricsManager to update itself from a new StatsdConfig. +// *Note*: only updateStatsdConfig() should be called from outside this file. +// All other functions are intermediate steps, created to make unit testing easier. + +// Possible update states for a component. PRESERVE means we should keep the existing one. +// REPLACE means we should create a new one because the existing one changed +// NEW means we should create a new one because one does not currently exist. +enum UpdateStatus { + UPDATE_UNKNOWN = 0, + UPDATE_PRESERVE = 1, + UPDATE_REPLACE = 2, + UPDATE_NEW = 3, +}; + +// Recursive function to determine if a matcher needs to be updated. +// input: +// [config]: the input StatsdConfig +// [matcherIdx]: the index of the current matcher to be updated +// [oldAtomMatchingTrackerMap]: matcher id to index mapping in the existing MetricsManager +// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers +// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig +// output: +// [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will +// be updated from UPDATE_UNKNOWN after this call. +// [cycleTracker]: intermediate param used during recursion. +// Returns whether the function was successful or not. +bool determineMatcherUpdateStatus( + const StatsdConfig& config, const int matcherIdx, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<UpdateStatus>& matchersToUpdate, std::vector<bool>& cycleTracker); + +// Updates the AtomMatchingTrackers. +// input: +// [config]: the input StatsdConfig +// [oldAtomMatchingTrackerMap]: existing matcher id to index mapping +// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers +// output: +// [allTagIds]: contains the set of all interesting tag ids to this config. +// [newAtomMatchingTrackerMap]: new matcher id to index mapping +// [newAtomMatchingTrackers]: stores the new AtomMatchingTrackers +// [replacedMatchers]: set of matcher ids that changed and have been replaced +bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + std::set<int>& allTagIds, + std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + std::set<int64_t>& replacedMatchers); + +// Recursive function to determine if a condition needs to be updated. +// input: +// [config]: the input StatsdConfig +// [conditionIdx]: the index of the current condition to be updated +// [oldConditionTrackerMap]: condition id to index mapping in the existing MetricsManager +// [oldConditionTrackers]: stores the existing ConditionTrackers +// [newConditionTrackerMap]: condition id to index mapping in the input StatsdConfig +// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced +// output: +// [conditionsToUpdate]: vector of the update status of each condition. The conditionIdx index will +// be updated from UPDATE_UNKNOWN after this call. +// [cycleTracker]: intermediate param used during recursion. +// Returns whether the function was successful or not. +bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + const std::unordered_map<int64_t, int>& newConditionTrackerMap, + const std::set<int64_t>& replacedMatchers, + std::vector<UpdateStatus>& conditionsToUpdate, + std::vector<bool>& cycleTracker); + +// Updates ConditionTrackers +// input: +// [config]: the input config +// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step. +// [replacedMatchers]: ids of replaced matchers. conditions depending on these must also be replaced +// [oldConditionTrackerMap]: existing matcher id to index mapping +// [oldConditionTrackers]: stores the existing ConditionTrackers +// output: +// [newConditionTrackerMap]: new condition id to index mapping +// [newConditionTrackers]: stores the sp to all the ConditionTrackers +// [trackerToConditionMap]: contains the mapping from the index of an atom matcher +// to indices of condition trackers that use the matcher +// [conditionCache]: stores the current conditions for each ConditionTracker +// [replacedConditions]: set of matcher ids that have changed and have been replaced +bool updateConditions(const ConfigKey& key, const StatsdConfig& config, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::set<int64_t>& replacedMatchers, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + std::unordered_map<int64_t, int>& newConditionTrackerMap, + std::vector<sp<ConditionTracker>>& newConditionTrackers, + std::unordered_map<int, std::vector<int>>& trackerToConditionMap, + std::vector<ConditionState>& conditionCache, + std::set<int64_t>& replacedConditions); + +// Updates the existing MetricsManager from a new StatsdConfig. +// Parameters are the members of MetricsManager. See MetricsManager for declaration. +bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, + const sp<StatsPullerManager>& pullerManager, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, + std::set<int>& allTagIds, + std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<sp<ConditionTracker>>& newConditionTrackers, + std::unordered_map<int64_t, int>& newConditionTrackerMap, + std::unordered_map<int, std::vector<int>>& trackerToConditionMap); + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index 8917c36bb608..3f40c90d515a 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -22,21 +22,23 @@ #include <inttypes.h> #include "FieldValue.h" -#include "MetricProducer.h" #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" #include "external/StatsPullerManager.h" -#include "matchers/CombinationLogMatchingTracker.h" +#include "hash.h" +#include "matchers/CombinationAtomMatchingTracker.h" #include "matchers/EventMatcherWizard.h" -#include "matchers/SimpleLogMatchingTracker.h" +#include "matchers/SimpleAtomMatchingTracker.h" #include "metrics/CountMetricProducer.h" #include "metrics/DurationMetricProducer.h" #include "metrics/EventMetricProducer.h" #include "metrics/GaugeMetricProducer.h" +#include "metrics/MetricProducer.h" #include "metrics/ValueMetricProducer.h" #include "state/StateManager.h" #include "stats_util.h" +using google::protobuf::MessageLite; using std::set; using std::unordered_map; using std::vector; @@ -59,20 +61,77 @@ bool hasLeafNode(const FieldMatcher& matcher) { return true; } +bool getMetricProtoHash(const MessageLite& metric, const int64_t id, const bool hasActivation, + const uint64_t activationHash, uint64_t& metricHash) { + string serializedMetric; + if (!metric.SerializeToString(&serializedMetric)) { + ALOGE("Unable to serialize metric %lld", (long long)id); + return false; + } + metricHash = Hash64(serializedMetric); + if (hasActivation) { + metricHash = Hash64(to_string(metricHash).append(to_string(activationHash))); + } + return true; +} + } // namespace -bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex, - const bool usedForDimension, - const vector<sp<LogMatchingTracker>>& allAtomMatchers, - const unordered_map<int64_t, int>& logTrackerMap, - unordered_map<int, std::vector<int>>& trackerToMetricMap, - int& logTrackerIndex) { - auto logTrackerIt = logTrackerMap.find(what); - if (logTrackerIt == logTrackerMap.end()) { +sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index, + const sp<UidMap>& uidMap) { + string serializedMatcher; + if (!logMatcher.SerializeToString(&serializedMatcher)) { + ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id()); + return nullptr; + } + uint64_t protoHash = Hash64(serializedMatcher); + switch (logMatcher.contents_case()) { + case AtomMatcher::ContentsCase::kSimpleAtomMatcher: + return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash, + logMatcher.simple_atom_matcher(), uidMap); + case AtomMatcher::ContentsCase::kCombination: + return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash); + default: + ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id()); + return nullptr; + } +} + +sp<ConditionTracker> createConditionTracker( + const ConfigKey& key, const Predicate& predicate, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + string serializedPredicate; + if (!predicate.SerializeToString(&serializedPredicate)) { + ALOGE("Unable to serialize predicate %lld", (long long)predicate.id()); + return nullptr; + } + uint64_t protoHash = Hash64(serializedPredicate); + switch (predicate.contents_case()) { + case Predicate::ContentsCase::kSimplePredicate: { + return new SimpleConditionTracker(key, predicate.id(), protoHash, index, + predicate.simple_predicate(), atomMatchingTrackerMap); + } + case Predicate::ContentsCase::kCombination: { + return new CombinationConditionTracker(predicate.id(), index, protoHash); + } + default: + ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id()); + return nullptr; + } +} + +bool handleMetricWithAtomMatchingTrackers( + const int64_t what, const int metricIndex, const bool usedForDimension, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + unordered_map<int, std::vector<int>>& trackerToMetricMap, int& logTrackerIndex) { + auto logTrackerIt = atomMatchingTrackerMap.find(what); + if (logTrackerIt == atomMatchingTrackerMap.end()) { ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)what); return false; } - if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) { + if (usedForDimension && + allAtomMatchingTrackers[logTrackerIt->second]->getAtomIds().size() > 1) { ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, " "the \"what\" can only about one atom type.", (long long)what); @@ -84,17 +143,17 @@ bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex, return true; } -bool handlePullMetricTriggerWithLogTrackers( +bool handlePullMetricTriggerWithAtomMatchingTrackers( const int64_t trigger, const int metricIndex, - const vector<sp<LogMatchingTracker>>& allAtomMatchers, - const unordered_map<int64_t, int>& logTrackerMap, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, unordered_map<int, std::vector<int>>& trackerToMetricMap, int& logTrackerIndex) { - auto logTrackerIt = logTrackerMap.find(trigger); - if (logTrackerIt == logTrackerMap.end()) { + auto logTrackerIt = atomMatchingTrackerMap.find(trigger); + if (logTrackerIt == atomMatchingTrackerMap.end()) { ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)trigger); return false; } - if (allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) { + if (allAtomMatchingTrackers[logTrackerIt->second]->getAtomIds().size() > 1) { ALOGE("AtomMatcher \"%lld\" has more than one tag ids." "Trigger can only be one atom type.", (long long)trigger); @@ -125,8 +184,6 @@ bool handleMetricWithConditions( ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition()); return false; } - allConditionTrackers[condition_it->second]->setSliced(true); - allConditionTrackers[it->second]->setSliced(true); } conditionIndex = condition_it->second; @@ -184,44 +241,55 @@ bool handleMetricWithStateLink(const FieldMatcher& stateMatcher, // to provide the producer with state about its activators and deactivators. // Returns false if there are errors. bool handleMetricActivation( - const StatsdConfig& config, - const int64_t metricId, - const int metricIndex, + const StatsdConfig& config, const int64_t metricId, const int metricIndex, const unordered_map<int64_t, int>& metricToActivationMap, - const unordered_map<int64_t, int>& logTrackerMap, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, bool& hasActivation, unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, vector<int>& metricsWithActivation, unordered_map<int, shared_ptr<Activation>>& eventActivationMap, - unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) { + unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap, + uint64_t& activationHash) { // Check if metric has an associated activation auto itr = metricToActivationMap.find(metricId); - if (itr == metricToActivationMap.end()) return true; + if (itr == metricToActivationMap.end()) { + hasActivation = false; + return true; + } + hasActivation = true; int activationIndex = itr->second; const MetricActivation& metricActivation = config.metric_activation(activationIndex); + string serializedActivation; + if (!metricActivation.SerializeToString(&serializedActivation)) { + ALOGE("Unable to serialize metric activation for metric %lld", (long long)metricId); + return false; + } + activationHash = Hash64(serializedActivation); + for (int i = 0; i < metricActivation.event_activation_size(); i++) { const EventActivation& activation = metricActivation.event_activation(i); - auto itr = logTrackerMap.find(activation.atom_matcher_id()); - if (itr == logTrackerMap.end()) { + auto itr = atomMatchingTrackerMap.find(activation.atom_matcher_id()); + if (itr == atomMatchingTrackerMap.end()) { ALOGE("Atom matcher not found for event activation."); return false; } - ActivationType activationType = (activation.has_activation_type()) ? - activation.activation_type() : metricActivation.activation_type(); - std::shared_ptr<Activation> activationWrapper = std::make_shared<Activation>( - activationType, activation.ttl_seconds() * NS_PER_SEC); + ActivationType activationType = (activation.has_activation_type()) + ? activation.activation_type() + : metricActivation.activation_type(); + std::shared_ptr<Activation> activationWrapper = + std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC); int atomMatcherIndex = itr->second; activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex); eventActivationMap.emplace(atomMatcherIndex, activationWrapper); if (activation.has_deactivation_atom_matcher_id()) { - itr = logTrackerMap.find(activation.deactivation_atom_matcher_id()); - if (itr == logTrackerMap.end()) { + itr = atomMatchingTrackerMap.find(activation.deactivation_atom_matcher_id()); + if (itr == atomMatchingTrackerMap.end()) { ALOGE("Atom matcher not found for event deactivation."); return false; } @@ -235,43 +303,34 @@ bool handleMetricActivation( return true; } -bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, - unordered_map<int64_t, int>& logTrackerMap, - vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) { +bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + unordered_map<int64_t, int>& atomMatchingTrackerMap, + vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + set<int>& allTagIds) { vector<AtomMatcher> matcherConfigs; const int atomMatcherCount = config.atom_matcher_size(); matcherConfigs.reserve(atomMatcherCount); - allAtomMatchers.reserve(atomMatcherCount); + allAtomMatchingTrackers.reserve(atomMatcherCount); for (int i = 0; i < atomMatcherCount; i++) { const AtomMatcher& logMatcher = config.atom_matcher(i); - - int index = allAtomMatchers.size(); - switch (logMatcher.contents_case()) { - case AtomMatcher::ContentsCase::kSimpleAtomMatcher: - allAtomMatchers.push_back(new SimpleLogMatchingTracker( - logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap)); - break; - case AtomMatcher::ContentsCase::kCombination: - allAtomMatchers.push_back( - new CombinationLogMatchingTracker(logMatcher.id(), index)); - break; - default: - ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id()); - return false; - // continue; + sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap); + if (tracker == nullptr) { + return false; } - if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) { + allAtomMatchingTrackers.push_back(tracker); + if (atomMatchingTrackerMap.find(logMatcher.id()) != atomMatchingTrackerMap.end()) { ALOGE("Duplicate AtomMatcher found!"); return false; } - logTrackerMap[logMatcher.id()] = index; + atomMatchingTrackerMap[logMatcher.id()] = i; matcherConfigs.push_back(logMatcher); } - vector<bool> stackTracker2(allAtomMatchers.size(), false); - for (auto& matcher : allAtomMatchers) { - if (!matcher->init(matcherConfigs, allAtomMatchers, logTrackerMap, stackTracker2)) { + vector<bool> stackTracker2(allAtomMatchingTrackers.size(), false); + for (auto& matcher : allAtomMatchingTrackers) { + if (!matcher->init(matcherConfigs, allAtomMatchingTrackers, atomMatchingTrackerMap, + stackTracker2)) { return false; } // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only. @@ -282,7 +341,7 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, } bool initConditions(const ConfigKey& key, const StatsdConfig& config, - const unordered_map<int64_t, int>& logTrackerMap, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, unordered_map<int64_t, int>& conditionTrackerMap, vector<sp<ConditionTracker>>& allConditionTrackers, unordered_map<int, std::vector<int>>& trackerToConditionMap, @@ -291,32 +350,21 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, const int conditionTrackerCount = config.predicate_size(); conditionConfigs.reserve(conditionTrackerCount); allConditionTrackers.reserve(conditionTrackerCount); - initialConditionCache.reserve(conditionTrackerCount); - std::fill(initialConditionCache.begin(), initialConditionCache.end(), ConditionState::kUnknown); + initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated); for (int i = 0; i < conditionTrackerCount; i++) { const Predicate& condition = config.predicate(i); - int index = allConditionTrackers.size(); - switch (condition.contents_case()) { - case Predicate::ContentsCase::kSimplePredicate: { - allConditionTrackers.push_back(new SimpleConditionTracker( - key, condition.id(), index, condition.simple_predicate(), logTrackerMap)); - break; - } - case Predicate::ContentsCase::kCombination: { - allConditionTrackers.push_back( - new CombinationConditionTracker(condition.id(), index)); - break; - } - default: - ALOGE("Predicate \"%lld\" malformed", (long long)condition.id()); - return false; + sp<ConditionTracker> tracker = + createConditionTracker(key, condition, i, atomMatchingTrackerMap); + if (tracker == nullptr) { + return false; } + allConditionTrackers.push_back(tracker); if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) { ALOGE("Duplicate Predicate found!"); return false; } - conditionTrackerMap[condition.id()] = index; + conditionTrackerMap[condition.id()] = i; conditionConfigs.push_back(condition); } @@ -327,7 +375,7 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, stackTracker, initialConditionCache)) { return false; } - for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) { + for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) { auto& conditionList = trackerToConditionMap[trackerIndex]; conditionList.push_back(i); } @@ -336,12 +384,20 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, } bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap, - unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps) { + unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, + map<int64_t, uint64_t>& stateProtoHashes) { for (int i = 0; i < config.state_size(); i++) { const State& state = config.state(i); const int64_t stateId = state.id(); stateAtomIdMap[stateId] = state.atom_id(); + string serializedState; + if (!state.SerializeToString(&serializedState)) { + ALOGE("Unable to serialize state %lld", (long long)stateId); + return false; + } + stateProtoHashes[stateId] = Hash64(serializedState); + const StateMap& stateMap = state.map(); for (auto group : stateMap.group()) { for (auto value : group.value()) { @@ -355,9 +411,9 @@ bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAt bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs, const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager, - const unordered_map<int64_t, int>& logTrackerMap, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, const unordered_map<int64_t, int>& conditionTrackerMap, - const vector<sp<LogMatchingTracker>>& allAtomMatchers, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, const unordered_map<int64_t, int>& stateAtomIdMap, const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, vector<sp<ConditionTracker>>& allConditionTrackers, @@ -370,7 +426,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, vector<int>& metricsWithActivation) { sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers); - sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers); + sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers); const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() + config.event_metric_size() + config.gauge_metric_size() + config.value_metric_size(); @@ -383,7 +439,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t const MetricActivation& metricActivation = config.metric_activation(i); int64_t metricId = metricActivation.metric_id(); if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) { - ALOGE("Metric %lld has multiple MetricActivations", (long long) metricId); + ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId); return false; } metricToActivationMap.insert({metricId, i}); @@ -401,10 +457,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t int metricIndex = allMetricProducers.size(); metricMap.insert({metric.id(), metricIndex}); int trackerIndex; - if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndex)) { return false; } @@ -436,18 +492,25 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t } } + bool hasActivation = false; unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + uint64_t activationHash; + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash); if (!success) return false; - sp<MetricProducer> countProducer = - new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard, - timeBaseTimeNs, currentTimeNs, eventActivationMap, - eventDeactivationMap, slicedStateAtoms, stateGroupMap); + uint64_t metricHash; + if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) { + return false; + } + + sp<MetricProducer> countProducer = new CountMetricProducer( + key, metric, conditionIndex, initialConditionCache, wizard, metricHash, + timeBaseTimeNs, currentTimeNs, eventActivationMap, eventDeactivationMap, + slicedStateAtoms, stateGroupMap); allMetricProducers.push_back(countProducer); } @@ -476,24 +539,27 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t int trackerIndices[3] = {-1, -1, -1}; if (!simplePredicate.has_start() || - !handleMetricWithLogTrackers(simplePredicate.start(), metricIndex, - metric.has_dimensions_in_what(), allAtomMatchers, - logTrackerMap, trackerToMetricMap, trackerIndices[0])) { + !handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndices[0])) { ALOGE("Duration metrics must specify a valid the start event matcher"); return false; } if (simplePredicate.has_stop() && - !handleMetricWithLogTrackers(simplePredicate.stop(), metricIndex, - metric.has_dimensions_in_what(), allAtomMatchers, - logTrackerMap, trackerToMetricMap, trackerIndices[1])) { + !handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndices[1])) { return false; } if (simplePredicate.has_stop_all() && - !handleMetricWithLogTrackers(simplePredicate.stop_all(), metricIndex, - metric.has_dimensions_in_what(), allAtomMatchers, - logTrackerMap, trackerToMetricMap, trackerIndices[2])) { + !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndices[2])) { return false; } @@ -542,19 +608,26 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t } } + bool hasActivation = false; unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + uint64_t activationHash; + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash); if (!success) return false; + uint64_t metricHash; + if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) { + return false; + } + sp<MetricProducer> durationMetric = new DurationMetricProducer( key, metric, conditionIndex, initialConditionCache, trackerIndices[0], - trackerIndices[1], trackerIndices[2], nesting, wizard, internalDimensions, - timeBaseTimeNs, currentTimeNs, eventActivationMap, eventDeactivationMap, - slicedStateAtoms, stateGroupMap); + trackerIndices[1], trackerIndices[2], nesting, wizard, metricHash, + internalDimensions, timeBaseTimeNs, currentTimeNs, eventActivationMap, + eventDeactivationMap, slicedStateAtoms, stateGroupMap); allMetricProducers.push_back(durationMetric); } @@ -569,8 +642,9 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t return false; } int trackerIndex; - if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allAtomMatchers, - logTrackerMap, trackerToMetricMap, trackerIndex)) { + if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, false, + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndex)) { return false; } @@ -589,17 +663,24 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t } } + bool hasActivation = false; unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + uint64_t activationHash; + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash); if (!success) return false; - sp<MetricProducer> eventMetric = - new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard, - timeBaseTimeNs, eventActivationMap, eventDeactivationMap); + uint64_t metricHash; + if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) { + return false; + } + + sp<MetricProducer> eventMetric = new EventMetricProducer( + key, metric, conditionIndex, initialConditionCache, wizard, metricHash, + timeBaseTimeNs, eventActivationMap, eventDeactivationMap); allMetricProducers.push_back(eventMetric); } @@ -625,14 +706,14 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t int metricIndex = allMetricProducers.size(); metricMap.insert({metric.id(), metricIndex}); int trackerIndex; - if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndex)) { return false; } - sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex); + sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex); // If it is pulled atom, it should be simple matcher with one tagId. if (atomMatcher->getAtomIds().size() != 1) { return false; @@ -678,18 +759,26 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t } } + bool hasActivation = false; unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; + uint64_t activationHash; bool success = handleMetricActivation( - config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - metricsWithActivation, eventActivationMap, eventDeactivationMap); + config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash); if (!success) return false; + uint64_t metricHash; + if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) { + return false; + } + sp<MetricProducer> valueProducer = new ValueMetricProducer( - key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex, - matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs, pullerManager, - eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap); + key, metric, conditionIndex, initialConditionCache, wizard, metricHash, + trackerIndex, matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs, + pullerManager, eventActivationMap, eventDeactivationMap, slicedStateAtoms, + stateGroupMap); allMetricProducers.push_back(valueProducer); } @@ -717,14 +806,14 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t int metricIndex = allMetricProducers.size(); metricMap.insert({metric.id(), metricIndex}); int trackerIndex; - if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, trackerIndex)) { return false; } - sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex); + sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex); // For GaugeMetric atom, it should be simple matcher with one tagId. if (atomMatcher->getAtomIds().size() != 1) { return false; @@ -743,12 +832,13 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) { return false; } - if (!handlePullMetricTriggerWithLogTrackers(metric.trigger_event(), metricIndex, - allAtomMatchers, logTrackerMap, - trackerToMetricMap, triggerTrackerIndex)) { + if (!handlePullMetricTriggerWithAtomMatchingTrackers( + metric.trigger_event(), metricIndex, allAtomMatchingTrackers, + atomMatchingTrackerMap, trackerToMetricMap, triggerTrackerIndex)) { return false; } - sp<LogMatchingTracker> triggerAtomMatcher = allAtomMatchers.at(triggerTrackerIndex); + sp<AtomMatchingTracker> triggerAtomMatcher = + allAtomMatchingTrackers.at(triggerTrackerIndex); triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin()); } @@ -773,18 +863,25 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t } } + bool hasActivation = false; unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + uint64_t activationHash; + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash); if (!success) return false; + uint64_t metricHash; + if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) { + return false; + } + sp<MetricProducer> gaugeProducer = new GaugeMetricProducer( - key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex, - matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseTimeNs, currentTimeNs, - pullerManager, eventActivationMap, eventDeactivationMap); + key, metric, conditionIndex, initialConditionCache, wizard, metricHash, + trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseTimeNs, + currentTimeNs, pullerManager, eventActivationMap, eventDeactivationMap); allMetricProducers.push_back(gaugeProducer); } for (int i = 0; i < config.no_report_metric_size(); ++i) { @@ -813,8 +910,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t return true; } -bool initAlerts(const StatsdConfig& config, - const unordered_map<int64_t, int>& metricProducerMap, +bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap, unordered_map<int64_t, int>& alertTrackerMap, const sp<AlarmMonitor>& anomalyAlarmMonitor, vector<sp<MetricProducer>>& allMetricProducers, @@ -832,8 +928,8 @@ bool initAlerts(const StatsdConfig& config, return false; } if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) { - ALOGW("invalid alert: threshold=%f num_buckets= %d", - alert.trigger_if_sum_gt(), alert.num_buckets()); + ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(), + alert.num_buckets()); return false; } const int metricIndex = itr->second; @@ -853,14 +949,13 @@ bool initAlerts(const StatsdConfig& config, } if (subscription.subscriber_information_case() == Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", - (long long)subscription.id()); + ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); return false; } const auto& itr = alertTrackerMap.find(subscription.rule_id()); if (itr == alertTrackerMap.end()) { ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); + (long long)subscription.id(), (long long)subscription.rule_id()); return false; } const int anomalyTrackerIndex = itr->second; @@ -870,12 +965,11 @@ bool initAlerts(const StatsdConfig& config, } bool initAlarms(const StatsdConfig& config, const ConfigKey& key, - const sp<AlarmMonitor>& periodicAlarmMonitor, - const int64_t timeBaseNs, const int64_t currentTimeNs, - vector<sp<AlarmTracker>>& allAlarmTrackers) { + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, vector<sp<AlarmTracker>>& allAlarmTrackers) { unordered_map<int64_t, int> alarmTrackerMap; int64_t startMillis = timeBaseNs / 1000 / 1000; - int64_t currentTimeMillis = currentTimeNs / 1000 /1000; + int64_t currentTimeMillis = currentTimeNs / 1000 / 1000; for (int i = 0; i < config.alarm_size(); i++) { const Alarm& alarm = config.alarm(i); if (alarm.offset_millis() <= 0) { @@ -888,8 +982,7 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, } alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size())); allAlarmTrackers.push_back( - new AlarmTracker(startMillis, currentTimeMillis, - alarm, key, periodicAlarmMonitor)); + new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor)); } for (int i = 0; i < config.subscription_size(); ++i) { const Subscription& subscription = config.subscription(i); @@ -898,14 +991,13 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, } if (subscription.subscriber_information_case() == Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", - (long long)subscription.id()); + ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); return false; } const auto& itr = alarmTrackerMap.find(subscription.rule_id()); if (itr == alarmTrackerMap.end()) { ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); + (long long)subscription.id(), (long long)subscription.rule_id()); return false; } const int trackerIndex = itr->second; @@ -914,14 +1006,17 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, return true; } -bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, const int64_t currentTimeNs, set<int>& allTagIds, - vector<sp<LogMatchingTracker>>& allAtomMatchers, + vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + unordered_map<int64_t, int>& atomMatchingTrackerMap, vector<sp<ConditionTracker>>& allConditionTrackers, + unordered_map<int64_t, int>& conditionTrackerMap, vector<sp<MetricProducer>>& allMetricProducers, + unordered_map<int64_t, int>& metricProducerMap, vector<sp<AnomalyTracker>>& allAnomalyTrackers, vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers, unordered_map<int, std::vector<int>>& conditionToMetricMap, @@ -930,37 +1025,35 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, unordered_map<int64_t, int>& alertTrackerMap, - vector<int>& metricsWithActivation, - std::set<int64_t>& noReportMetricIds) { - unordered_map<int64_t, int> logTrackerMap; - unordered_map<int64_t, int> conditionTrackerMap; + vector<int>& metricsWithActivation, map<int64_t, uint64_t>& stateProtoHashes, + set<int64_t>& noReportMetricIds) { vector<ConditionState> initialConditionCache; - unordered_map<int64_t, int> metricProducerMap; unordered_map<int64_t, int> stateAtomIdMap; unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps; - if (!initLogTrackers(config, uidMap, logTrackerMap, allAtomMatchers, allTagIds)) { - ALOGE("initLogMatchingTrackers failed"); + if (!initAtomMatchingTrackers(config, uidMap, atomMatchingTrackerMap, allAtomMatchingTrackers, + allTagIds)) { + ALOGE("initAtomMatchingTrackers failed"); return false; } - VLOG("initLogMatchingTrackers succeed..."); + VLOG("initAtomMatchingTrackers succeed..."); - if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers, - trackerToConditionMap, initialConditionCache)) { + if (!initConditions(key, config, atomMatchingTrackerMap, conditionTrackerMap, + allConditionTrackers, trackerToConditionMap, initialConditionCache)) { ALOGE("initConditionTrackers failed"); return false; } - if (!initStates(config, stateAtomIdMap, allStateGroupMaps)) { + if (!initStates(config, stateAtomIdMap, allStateGroupMaps, stateProtoHashes)) { ALOGE("initStates failed"); return false; } - if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, logTrackerMap, - conditionTrackerMap, allAtomMatchers, stateAtomIdMap, allStateGroupMaps, - allConditionTrackers, initialConditionCache, allMetricProducers, - conditionToMetricMap, trackerToMetricMap, metricProducerMap, noReportMetricIds, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - metricsWithActivation)) { + if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, atomMatchingTrackerMap, + conditionTrackerMap, allAtomMatchingTrackers, stateAtomIdMap, + allStateGroupMaps, allConditionTrackers, initialConditionCache, + allMetricProducers, conditionToMetricMap, trackerToMetricMap, + metricProducerMap, noReportMetricIds, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, metricsWithActivation)) { ALOGE("initMetricProducers failed"); return false; } @@ -969,8 +1062,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& ALOGE("initAlerts failed"); return false; } - if (!initAlarms(config, key, periodicAlarmMonitor, - timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) { + if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, + allPeriodicAlarmTrackers)) { ALOGE("initAlarms failed"); return false; } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h index 96b5c26ff789..4979c3051133 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h @@ -20,41 +20,63 @@ #include <unordered_map> #include <vector> -#include "../anomaly/AlarmTracker.h" -#include "../condition/ConditionTracker.h" -#include "../external/StatsPullerManager.h" -#include "../matchers/LogMatchingTracker.h" -#include "../metrics/MetricProducer.h" +#include "anomaly/AlarmTracker.h" +#include "condition/ConditionTracker.h" +#include "external/StatsPullerManager.h" +#include "matchers/AtomMatchingTracker.h" +#include "metrics/MetricProducer.h" namespace android { namespace os { namespace statsd { +// Helper functions for creating individual config components from StatsdConfig. +// Should only be called from metrics_manager_util and config_update_utils. + +// Create a AtomMatchingTracker. +// input: +// [logMatcher]: the input AtomMatcher from the StatsdConfig +// [index]: the index of the matcher +// output: +// new AtomMatchingTracker, or null if the tracker is unable to be created +sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index, + const sp<UidMap>& uidMap); + +// Create a ConditionTracker. +// input: +// [predicate]: the input Predicate from the StatsdConfig +// [index]: the index of the condition tracker +// [atomMatchingTrackerMap]: map of atom matcher id to its index in allAtomMatchingTrackers +// output: +// new ConditionTracker, or null if the tracker is unable to be created +sp<ConditionTracker> createConditionTracker( + const ConfigKey& key, const Predicate& predicate, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap); + // Helper functions for MetricsManager to initialize from StatsdConfig. // *Note*: only initStatsdConfig() should be called from outside. // All other functions are intermediate // steps, created to make unit tests easier. And most of the parameters in these // functions are temporary objects in the initialization phase. -// Initialize the LogMatchingTrackers. +// Initialize the AtomMatchingTrackers. // input: // [key]: the config key that this config belongs to // [config]: the input StatsdConfig // output: -// [logTrackerMap]: this map should contain matcher name to index mapping -// [allAtomMatchers]: should store the sp to all the LogMatchingTracker +// [atomMatchingTrackerMap]: this map should contain matcher name to index mapping +// [allAtomMatchingTrackers]: should store the sp to all the AtomMatchingTracker // [allTagIds]: contains the set of all interesting tag ids to this config. -bool initLogTrackers(const StatsdConfig& config, - const UidMap& uidMap, - std::unordered_map<int64_t, int>& logTrackerMap, - std::vector<sp<LogMatchingTracker>>& allAtomMatchers, - std::set<int>& allTagIds); +bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + std::set<int>& allTagIds); // Initialize ConditionTrackers // input: // [key]: the config key that this config belongs to // [config]: the input config -// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step. +// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step. // output: // [conditionTrackerMap]: this map should contain condition name to index mapping // [allConditionTrackers]: stores the sp to all the ConditionTrackers @@ -62,11 +84,10 @@ bool initLogTrackers(const StatsdConfig& config, // log tracker to condition trackers that use the log tracker // [initialConditionCache]: stores the initial conditions for each ConditionTracker bool initConditions(const ConfigKey& key, const StatsdConfig& config, - const std::unordered_map<int64_t, int>& logTrackerMap, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, std::unordered_map<int64_t, int>& conditionTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, std::unordered_map<int, std::vector<int>>& trackerToConditionMap, - std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, std::vector<ConditionState>& initialConditionCache); // Initialize State maps using State protos in the config. These maps will @@ -77,15 +98,17 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, // [stateAtomIdMap]: this map should contain the mapping from state ids to atom ids // [allStateGroupMaps]: this map should contain the mapping from states ids and state // values to state group ids for all states +// [stateProtoHashes]: contains a map of state id to the hash of the State proto from the config bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap, - unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps); + unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, + std::map<int64_t, uint64_t>& stateProtoHashes); // Initialize MetricProducers. // input: // [key]: the config key that this config belongs to // [config]: the input config // [timeBaseSec]: start time base for all metrics -// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step. +// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step. // [conditionTrackerMap]: condition name to index mapping // [stateAtomIdMap]: contains the mapping from state ids to atom ids // [allStateGroupMaps]: contains the mapping from atom ids and state values to @@ -97,11 +120,10 @@ bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAt // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index. bool initMetrics( const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs, - const int64_t currentTimeNs, UidMap& uidMap, const sp<StatsPullerManager>& pullerManager, - const std::unordered_map<int64_t, int>& logTrackerMap, + const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, const std::unordered_map<int64_t, int>& conditionTrackerMap, - const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, - const vector<sp<LogMatchingTracker>>& allAtomMatchers, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, const unordered_map<int64_t, int>& stateAtomIdMap, const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, vector<sp<ConditionTracker>>& allConditionTrackers, @@ -116,14 +138,17 @@ bool initMetrics( // Initialize MetricsManager from StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. -bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, const int64_t currentTimeNs, std::set<int>& allTagIds, - std::vector<sp<LogMatchingTracker>>& allAtomMatchers, + std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + std::unordered_map<int64_t, int>& atomMatchingTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, + std::unordered_map<int64_t, int>& conditionTrackerMap, std::vector<sp<MetricProducer>>& allMetricProducers, + std::unordered_map<int64_t, int>& metricProducerMap, vector<sp<AnomalyTracker>>& allAnomalyTrackers, vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers, std::unordered_map<int, std::vector<int>>& conditionToMetricMap, @@ -133,6 +158,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::unordered_map<int64_t, int>& alertTrackerMap, vector<int>& metricsWithActivation, + std::map<int64_t, uint64_t>& stateProtoHashes, std::set<int64_t>& noReportMetricIds); } // namespace statsd diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h index 6c50a8c41770..1bc84c5433f9 100644 --- a/cmds/statsd/src/packages/PackageInfoListener.h +++ b/cmds/statsd/src/packages/PackageInfoListener.h @@ -17,6 +17,8 @@ #ifndef STATSD_PACKAGE_INFO_LISTENER_H #define STATSD_PACKAGE_INFO_LISTENER_H +#include <utils/RefBase.h> + #include <string> namespace android { diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index 22250aee402e..622321b804ec 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -17,7 +17,6 @@ #pragma once #include "config/ConfigKey.h" -#include "config/ConfigListener.h" #include "packages/PackageInfoListener.h" #include "stats_util.h" diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index fd883c29dba0..9d8f0c24e253 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -191,7 +191,7 @@ void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEve mProto.clear(); int count = 0; for (const auto& event : data) { - if (matchesSimple(*mUidMap, matcher, *event)) { + if (matchesSimple(mUidMap, matcher, *event)) { count++; uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE | util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM); @@ -209,7 +209,7 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) { mProto.clear(); for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) { - if (matchesSimple(*mUidMap, matcher, event)) { + if (matchesSimple(mUidMap, matcher, event)) { uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE | util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM); event.ToProto(mProto); diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index eb65dc6979c5..10e065e4113f 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -97,7 +97,7 @@ bool parseProtoOutputStream(ProtoOutputStream& protoOutput, T* message) { return message->ParseFromArray(pbBytes.c_str(), pbBytes.size()); } -// Checks the truncate timestamp annotation as well as the blacklisted range of 300,000 - 304,999. +// Checks the truncate timestamp annotation as well as the restricted range of 300,000 - 304,999. // Returns the truncated timestamp to the nearest 5 minutes if needed. int64_t truncateTimestampIfNecessary(const LogEvent& event); diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 6264c075426a..92cd04f37ee0 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -110,7 +110,7 @@ void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t ti } // anonymous namespace TEST(AtomMatcherTest, TestSimpleMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; @@ -129,7 +129,7 @@ TEST(AtomMatcherTest, TestSimpleMatcher) { } TEST(AtomMatcherTest, TestAttributionMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); std::vector<int> attributionUids = {1111, 2222, 3333}; std::vector<string> attributionTags = {"location1", "location2", "location3"}; @@ -204,7 +204,7 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { "pkg0"); EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); - uidMap.updateMap( + 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")}, @@ -356,8 +356,8 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { } TEST(AtomMatcherTest, TestUidFieldMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new 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")}, @@ -392,8 +392,8 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) { } TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new 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")}, @@ -453,8 +453,8 @@ TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { } TEST(AtomMatcherTest, TestEqAnyStringMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new 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")}, @@ -517,7 +517,7 @@ TEST(AtomMatcherTest, TestEqAnyStringMatcher) { } TEST(AtomMatcherTest, TestBoolMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -550,7 +550,7 @@ TEST(AtomMatcherTest, TestBoolMatcher) { } TEST(AtomMatcherTest, TestStringMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -568,7 +568,7 @@ TEST(AtomMatcherTest, TestStringMatcher) { } TEST(AtomMatcherTest, TestMultiFieldsMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -597,7 +597,7 @@ TEST(AtomMatcherTest, TestMultiFieldsMatcher) { } TEST(AtomMatcherTest, TestIntComparisonMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -654,7 +654,7 @@ TEST(AtomMatcherTest, TestIntComparisonMatcher) { } TEST(AtomMatcherTest, TestFloatComparisonMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp index 6259757fe092..2dd774e7dfc9 100644 --- a/cmds/statsd/tests/MetricsManager_test.cpp +++ b/cmds/statsd/tests/MetricsManager_test.cpp @@ -23,12 +23,12 @@ #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "metrics/metrics_test_helper.h" #include "src/condition/ConditionTracker.h" -#include "src/matchers/LogMatchingTracker.h" +#include "src/matchers/AtomMatchingTracker.h" #include "src/metrics/CountMetricProducer.h" #include "src/metrics/GaugeMetricProducer.h" #include "src/metrics/MetricProducer.h" #include "src/metrics/ValueMetricProducer.h" -#include "src/metrics/metrics_manager_util.h" +#include "src/metrics/parsing_utils/metrics_manager_util.h" #include "src/state/StateManager.h" #include "statsd_test_util.h" @@ -48,7 +48,6 @@ namespace statsd { namespace { const ConfigKey kConfigKey(0, 12345); -const long kAlertId = 3; const long timeBaseSec = 1000; @@ -90,287 +89,6 @@ StatsdConfig buildGoodConfig() { metric->set_bucket(ONE_MINUTE); metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - config.add_no_report_metric(3); - - auto alert = config.add_alert(); - alert->set_id(kAlertId); - alert->set_metric_id(3); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildCircleMatchers() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("SCREEN_IS_ON")); - // Circle dependency - combination->add_matcher(StringToId("SCREEN_ON_OR_OFF")); - - return config; -} - -StatsdConfig buildAlertWithUnknownMetric() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("SCREEN_IS_ON")); - metric->set_bucket(ONE_MINUTE); - metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); - metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - auto alert = config.add_alert(); - alert->set_id(3); - alert->set_metric_id(2); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildMissingMatchers() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("SCREEN_IS_ON")); - // undefined matcher - combination->add_matcher(StringToId("ABC")); - - return config; -} - -StatsdConfig buildMissingPredicate() { - StatsdConfig config; - config.set_id(12345); - - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("SCREEN_EVENT")); - metric->set_bucket(ONE_MINUTE); - metric->set_condition(StringToId("SOME_CONDITION")); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_EVENT")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2); - - return config; -} - -StatsdConfig buildDimensionMetricsWithMultiTags() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_VERY_LOW")); - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW")); - simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(3); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_LOW")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("BATTERY_VERY_LOW")); - combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW")); - - // Count process state changes, slice by uid, while SCREEN_IS_OFF - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("BATTERY_LOW")); - metric->set_bucket(ONE_MINUTE); - // This case is interesting. We want to dimension across two atoms. - metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - auto alert = config.add_alert(); - alert->set_id(kAlertId); - alert->set_metric_id(3); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildCirclePredicates() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); - - simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); - - auto condition = config.add_predicate(); - condition->set_id(StringToId("SCREEN_IS_ON")); - SimplePredicate* simplePredicate = condition->mutable_simple_predicate(); - simplePredicate->set_start(StringToId("SCREEN_IS_ON")); - simplePredicate->set_stop(StringToId("SCREEN_IS_OFF")); - - condition = config.add_predicate(); - condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF")); - - Predicate_Combination* combination = condition->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_predicate(StringToId("SCREEN_IS_ON")); - combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF")); - - return config; -} - -StatsdConfig buildConfigWithDifferentPredicates() { - StatsdConfig config; - config.set_id(12345); - - auto pulledAtomMatcher = - CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE); - *config.add_atom_matcher() = pulledAtomMatcher; - auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher(); - *config.add_atom_matcher() = screenOnAtomMatcher; - auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher(); - *config.add_atom_matcher() = screenOffAtomMatcher; - auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher(); - *config.add_atom_matcher() = batteryNoneAtomMatcher; - auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher(); - *config.add_atom_matcher() = batteryUsbAtomMatcher; - - // Simple condition with InitialValue set to default (unknown). - auto screenOnUnknownPredicate = CreateScreenIsOnPredicate(); - *config.add_predicate() = screenOnUnknownPredicate; - - // Simple condition with InitialValue set to false. - auto screenOnFalsePredicate = config.add_predicate(); - screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse")); - SimplePredicate* simpleScreenOnFalsePredicate = - screenOnFalsePredicate->mutable_simple_predicate(); - simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id()); - simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id()); - simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); - - // Simple condition with InitialValue set to false. - auto onBatteryFalsePredicate = config.add_predicate(); - onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse")); - SimplePredicate* simpleOnBatteryFalsePredicate = - onBatteryFalsePredicate->mutable_simple_predicate(); - simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id()); - simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id()); - simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); - - // Combination condition with both simple condition InitialValues set to false. - auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate(); - screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse")); - screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation( - LogicalOperation::AND); - addPredicateToPredicateCombination(*screenOnFalsePredicate, - screenOnFalseOnBatteryFalsePredicate); - addPredicateToPredicateCombination(*onBatteryFalsePredicate, - screenOnFalseOnBatteryFalsePredicate); - - // Combination condition with one simple condition InitialValue set to unknown and one set to - // false. - auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate(); - screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse")); - screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation( - LogicalOperation::AND); - addPredicateToPredicateCombination(screenOnUnknownPredicate, - screenOnUnknownOnBatteryFalsePredicate); - addPredicateToPredicateCombination(*onBatteryFalsePredicate, - screenOnUnknownOnBatteryFalsePredicate); - - // Simple condition metric with initial value false. - ValueMetric* metric1 = config.add_value_metric(); - metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse")); - metric1->set_what(pulledAtomMatcher.id()); - *metric1->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric1->set_bucket(FIVE_MINUTES); - metric1->set_condition(screenOnFalsePredicate->id()); - - // Simple condition metric with initial value unknown. - ValueMetric* metric2 = config.add_value_metric(); - metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown")); - metric2->set_what(pulledAtomMatcher.id()); - *metric2->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric2->set_bucket(FIVE_MINUTES); - metric2->set_condition(screenOnUnknownPredicate.id()); - - // Combination condition metric with initial values false and false. - ValueMetric* metric3 = config.add_value_metric(); - metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse")); - metric3->set_what(pulledAtomMatcher.id()); - *metric3->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric3->set_bucket(FIVE_MINUTES); - metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id()); - - // Combination condition metric with initial values unknown and false. - ValueMetric* metric4 = config.add_value_metric(); - metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse")); - metric4->set_what(pulledAtomMatcher.id()); - *metric4->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric4->set_bucket(FIVE_MINUTES); - metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id()); - return config; } @@ -379,274 +97,6 @@ bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) { } } // anonymous namespace -TEST(MetricsManagerTest, TestInitialConditions) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildConfigWithDifferentPredicates(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_TRUE(initStatsdConfig( - kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, - noReportMetricIds)); - ASSERT_EQ(4u, allMetricProducers.size()); - ASSERT_EQ(5u, allConditionTrackers.size()); - - ConditionKey queryKey; - vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated); - - allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); - allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); - EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[1]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[2]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[3]); - EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]); - - EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition); - EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition); - EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition); - EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition); -} - -TEST(MetricsManagerTest, TestGoodConfig) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); - ASSERT_EQ(1u, allMetricProducers.size()); - ASSERT_EQ(1u, allAnomalyTrackers.size()); - ASSERT_EQ(1u, noReportMetricIds.size()); - ASSERT_EQ(1u, alertTrackerMap.size()); - EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end()); - EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0); -} - -TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildDimensionMetricsWithMultiTags(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildCircleMatchers(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestMissingMatchers) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildMissingMatchers(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestMissingPredicate) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildMissingPredicate(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestCirclePredicateDependency) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildCirclePredicates(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, testAlertWithUnknownMetric) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildAlertWithUnknownMetric(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - TEST(MetricsManagerTest, TestLogSources) { string app1 = "app1"; set<int32_t> app1Uids = {1111, 11111}; @@ -680,7 +130,7 @@ TEST(MetricsManagerTest, TestLogSources) { sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); + StatsdConfig config; config.add_allowed_log_source("AID_SYSTEM"); config.add_allowed_log_source(app1); config.add_default_pull_packages("AID_SYSTEM"); @@ -744,7 +194,7 @@ TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) { sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); + StatsdConfig config; config.add_whitelisted_atom_ids(3); config.add_whitelisted_atom_ids(4); diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 1e6680c47567..1409b621fdf6 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -68,7 +68,7 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) { sp<StatsPullerManager> pullerManager = new StatsPullerManager(); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - // Construct the processor with a dummy sendBroadcast function that does nothing. + // Construct the processor with a no-op sendBroadcast function that does nothing. StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, [](const int&, const vector<int64_t>&) {return true;}); @@ -896,8 +896,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_TRUE(metricProducer2->isActive()); int i = 0; - for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { - if (metricsManager1->mAllAtomMatchers[i]->getId() == + for (; i < metricsManager1->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManager1->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger1->atom_matcher_id()) { break; } @@ -908,8 +908,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_EQ(kNotActive, activation1->state); i = 0; - for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { - if (metricsManager1->mAllAtomMatchers[i]->getId() == + for (; i < metricsManager1->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManager1->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger2->atom_matcher_id()) { break; } @@ -981,8 +981,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_TRUE(metricProducer1002->isActive()); i = 0; - for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { - if (metricsManager1001->mAllAtomMatchers[i]->getId() == + for (; i < metricsManager1001->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManager1001->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger1->atom_matcher_id()) { break; } @@ -993,8 +993,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_EQ(kNotActive, activation1001_1->state); i = 0; - for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { - if (metricsManager1001->mAllAtomMatchers[i]->getId() == + for (; i < metricsManager1001->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManager1001->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger2->atom_matcher_id()) { break; } @@ -1082,8 +1082,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); i = 0; - for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + for (; i < metricsManagerTimeBase3->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger1->atom_matcher_id()) { break; } @@ -1094,8 +1094,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_EQ(kNotActive, activationTimeBase3_1->state); i = 0; - for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + for (; i < metricsManagerTimeBase3->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger2->atom_matcher_id()) { break; } @@ -1184,8 +1184,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_TRUE(metricProducerTimeBase4_2->isActive()); i = 0; - for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() == + for (; i < metricsManagerTimeBase4->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger1->atom_matcher_id()) { break; } @@ -1196,8 +1196,8 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { EXPECT_EQ(kNotActive, activationTimeBase4_1->state); i = 0; - for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() == + for (; i < metricsManagerTimeBase4->mAllAtomMatchingTrackers.size(); i++) { + if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[i]->getId() == metric1ActivationTrigger2->atom_matcher_id()) { break; } @@ -1585,8 +1585,8 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_TRUE(metricProducer3->isActive()); // Check event activations. - ASSERT_EQ(metricsManager1->mAllAtomMatchers.size(), 4); - EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(), + ASSERT_EQ(metricsManager1->mAllAtomMatchingTrackers.size(), 4); + EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[0]->getId(), metric1ActivationTrigger1->atom_matcher_id()); const auto& activation1 = metricProducer1->mEventActivationMap.at(0); EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns); @@ -1594,7 +1594,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kNotActive, activation1->state); EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType); - EXPECT_EQ(metricsManager1->mAllAtomMatchers[1]->getId(), + EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[1]->getId(), metric1ActivationTrigger2->atom_matcher_id()); const auto& activation2 = metricProducer1->mEventActivationMap.at(1); EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns); @@ -1602,7 +1602,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kNotActive, activation2->state); EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType); - EXPECT_EQ(metricsManager1->mAllAtomMatchers[2]->getId(), + EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[2]->getId(), metric2ActivationTrigger1->atom_matcher_id()); const auto& activation3 = metricProducer2->mEventActivationMap.at(2); EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns); @@ -1610,7 +1610,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kNotActive, activation3->state); EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType); - EXPECT_EQ(metricsManager1->mAllAtomMatchers[3]->getId(), + EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[3]->getId(), metric2ActivationTrigger2->atom_matcher_id()); const auto& activation4 = metricProducer2->mEventActivationMap.at(3); EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns); @@ -1685,8 +1685,8 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { // Activation 1 is kActiveOnBoot. // Activation 2 and 3 are not active. // Activation 4 is active. - ASSERT_EQ(metricsManager2->mAllAtomMatchers.size(), 4); - EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(), + ASSERT_EQ(metricsManager2->mAllAtomMatchingTrackers.size(), 4); + EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[0]->getId(), metric1ActivationTrigger1->atom_matcher_id()); const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0); EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns); @@ -1694,7 +1694,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kActiveOnBoot, activation1001->state); EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType); - EXPECT_EQ(metricsManager2->mAllAtomMatchers[1]->getId(), + EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[1]->getId(), metric1ActivationTrigger2->atom_matcher_id()); const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1); EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns); @@ -1702,7 +1702,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kNotActive, activation1002->state); EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType); - EXPECT_EQ(metricsManager2->mAllAtomMatchers[2]->getId(), + EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[2]->getId(), metric2ActivationTrigger1->atom_matcher_id()); const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2); EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns); @@ -1710,7 +1710,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { EXPECT_EQ(kNotActive, activation1003->state); EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType); - EXPECT_EQ(metricsManager2->mAllAtomMatchers[3]->getId(), + EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[3]->getId(), metric2ActivationTrigger2->atom_matcher_id()); const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3); EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns); diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp index 293e8ed1c44c..33bdc64333e0 100644 --- a/cmds/statsd/tests/UidMap_test.cpp +++ b/cmds/statsd/tests/UidMap_test.cpp @@ -44,7 +44,7 @@ TEST(UidMapTest, TestIsolatedUID) { sp<StatsPullerManager> pullerManager = new StatsPullerManager(); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; - // Construct the processor with a dummy sendBroadcast function that does nothing. + // Construct the processor with a no-op sendBroadcast function that does nothing. StatsLogProcessor p( m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 07b5311b1207..8998b5f98df5 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -39,6 +39,7 @@ const ConfigKey kConfigKey(0, 12345); const int ATTRIBUTION_NODE_FIELD_ID = 1; const int ATTRIBUTION_UID_FIELD_ID = 1; const int TAG_ID = 1; +const uint64_t protoHash = 0x123456789; SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse, bool outputSlicedUid, Position position) { @@ -123,7 +124,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*tracker index*/, simplePredicate, trackerNameIndexMap); @@ -177,7 +178,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*tracker index*/, simplePredicate, trackerNameIndexMap); @@ -231,8 +232,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/, - simplePredicate, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, + 0 /*tracker index*/, simplePredicate, + trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); // This event is not accessed in this test besides dimensions which is why this is okay. @@ -317,7 +319,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); @@ -392,7 +394,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); @@ -514,7 +516,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); @@ -610,7 +612,7 @@ TEST(SimpleConditionTrackerTest, TestStopAll) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp index 95e301002a1b..70e7365ec238 100644 --- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp @@ -12,14 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <android/binder_ibinder.h> +#include <android/binder_interface_utils.h> #include <gtest/gtest.h> -#include "src/anomaly/DurationAnomalyTracker.h" +#include <vector> + #include "src/StatsLogProcessor.h" +#include "src/StatsService.h" +#include "src/anomaly/DurationAnomalyTracker.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" -#include <vector> +using ::ndk::SharedRefBase; namespace android { namespace os { @@ -29,6 +34,9 @@ namespace statsd { namespace { +const int kConfigKey = 789130124; +const int kCallingUid = 0; + StatsdConfig CreateStatsdConfig(int num_buckets, uint64_t threshold_ns, DurationMetric::AggregationType aggregationType, @@ -89,6 +97,13 @@ MetricDimensionKey dimensionKey2( (int32_t)0x02010101), Value((int32_t)222))}), DEFAULT_DIMENSION_KEY); +void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) { + string str; + config.SerializeToString(&str); + std::vector<uint8_t> configAsVec(str.begin(), str.end()); + service->addConfiguration(kConfigKey, configAsVec, kCallingUid); +} + } // namespace TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { @@ -98,16 +113,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -158,12 +175,13 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, (uint32_t)alarmFiredTimestampSec0); + EXPECT_EQ(alarmFiredTimestampSec0, + processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec()); // Anomaly alarm fired. - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(alarmFiredTimestampSec0)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); + auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC); + processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); @@ -179,39 +197,39 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock wl1. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, - attributionUids2, attributionTags2, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC, (uint64_t)alarmFiredTimestampSec1); // Release wakelock wl1. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( static_cast<uint32_t>(alarmFiredTimestampSec1)); ASSERT_EQ(0u, alarmSet.size()); // Acquire wakelock wl1 near the end of bucket #0. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Release the event at early bucket #1. - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Anomaly detected when stopping the alarm. The refractory period does not change. EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, @@ -236,17 +254,17 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { // Condition turns true. screen_off_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, + CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); processor->OnLogEvent(screen_off_event.get()); EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Condition turns to false. - screen_on_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1, - android::view::DisplayStateEnum::DISPLAY_STATE_ON); - processor->OnLogEvent(screen_on_event.get()); + int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1; + screen_on_event = CreateScreenStateChangedEvent( + condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + processor->OnLogEvent(screen_on_event.get(), condition_false_time); // Condition turns to false. Cancelled the alarm. EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Detected one anomaly. @@ -262,12 +280,11 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(release_event.get()); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } @@ -279,16 +296,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -298,96 +317,97 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { // Acquire wakelock "wc1" in bucket #0. auto acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #0. - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc1" in bucket #1. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, - attributionUids2, attributionTags2, "wl1"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1, + attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc2" in bucket #2. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids3, attributionTags3, "wl2"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2, + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Release wakelock "wc2" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Acquire wakelock "wc1" in bucket #2. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / - NS_PER_SEC + - 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4, - attributionUids3, attributionTags3, "wl2"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5, + attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); + release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time + 4); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered. - EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + + EXPECT_EQ(refractory_period_sec + + (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) / + NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); } @@ -396,20 +416,22 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { const int num_buckets = 2; const uint64_t threshold_ns = 3 * NS_PER_SEC; auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; - const uint64_t alert_id = config.alert(0).id(); + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC; config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); + + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -418,81 +440,81 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { processor->OnLogEvent(screen_off_event.get()); // Acquire wakelock "wc1" in bucket #0. - auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100, + auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire the wakelock "wc1" again. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); // The alarm does not change. - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Anomaly alarm fired late. - const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet); + const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; + auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs); + processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Within the refractory period. No anomaly. EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // A new wakelock, but still within refractory period. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + release_event = + CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); // Still in the refractory period. No anomaly. processor->OnLogEvent(release_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } diff --git a/cmds/statsd/tests/external/StatsPullerManager_test.cpp b/cmds/statsd/tests/external/StatsPullerManager_test.cpp index c76e85ec75e6..0d539f477016 100644 --- a/cmds/statsd/tests/external/StatsPullerManager_test.cpp +++ b/cmds/statsd/tests/external/StatsPullerManager_test.cpp @@ -89,10 +89,10 @@ public: sp<StatsPullerManager> createPullerManagerAndRegister() { sp<StatsPullerManager> pullerManager = new StatsPullerManager(); shared_ptr<FakePullAtomCallback> cb1 = SharedRefBase::make<FakePullAtomCallback>(uid1); - pullerManager->RegisterPullAtomCallback(uid1, pullTagId1, coolDownNs, timeoutNs, {}, cb1, true); + pullerManager->RegisterPullAtomCallback(uid1, pullTagId1, coolDownNs, timeoutNs, {}, cb1); shared_ptr<FakePullAtomCallback> cb2 = SharedRefBase::make<FakePullAtomCallback>(uid2); - pullerManager->RegisterPullAtomCallback(uid2, pullTagId1, coolDownNs, timeoutNs, {}, cb2, true); - pullerManager->RegisterPullAtomCallback(uid1, pullTagId2, coolDownNs, timeoutNs, {}, cb1, true); + pullerManager->RegisterPullAtomCallback(uid2, pullTagId1, coolDownNs, timeoutNs, {}, cb2); + pullerManager->RegisterPullAtomCallback(uid1, pullTagId2, coolDownNs, timeoutNs, {}, cb1); return pullerManager; } } // anonymous namespace @@ -101,14 +101,14 @@ TEST(StatsPullerManagerTest, TestPullInvalidUid) { sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister(); vector<shared_ptr<LogEvent>> data; - EXPECT_FALSE(pullerManager->Pull(pullTagId1, {unregisteredUid}, /*timestamp =*/1, &data, true)); + EXPECT_FALSE(pullerManager->Pull(pullTagId1, {unregisteredUid}, /*timestamp =*/1, &data)); } TEST(StatsPullerManagerTest, TestPullChoosesCorrectUid) { sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister(); vector<shared_ptr<LogEvent>> data; - EXPECT_TRUE(pullerManager->Pull(pullTagId1, {uid1}, /*timestamp =*/1, &data, true)); + EXPECT_TRUE(pullerManager->Pull(pullTagId1, {uid1}, /*timestamp =*/1, &data)); ASSERT_EQ(data.size(), 1); EXPECT_EQ(data[0]->GetTagId(), pullTagId1); ASSERT_EQ(data[0]->getValues().size(), 1); @@ -121,7 +121,7 @@ TEST(StatsPullerManagerTest, TestPullInvalidConfigKey) { pullerManager->RegisterPullUidProvider(configKey, uidProvider); vector<shared_ptr<LogEvent>> data; - EXPECT_FALSE(pullerManager->Pull(pullTagId1, badConfigKey, /*timestamp =*/1, &data, true)); + EXPECT_FALSE(pullerManager->Pull(pullTagId1, badConfigKey, /*timestamp =*/1, &data)); } TEST(StatsPullerManagerTest, TestPullConfigKeyGood) { @@ -130,7 +130,7 @@ TEST(StatsPullerManagerTest, TestPullConfigKeyGood) { pullerManager->RegisterPullUidProvider(configKey, uidProvider); vector<shared_ptr<LogEvent>> data; - EXPECT_TRUE(pullerManager->Pull(pullTagId1, configKey, /*timestamp =*/1, &data, true)); + EXPECT_TRUE(pullerManager->Pull(pullTagId1, configKey, /*timestamp =*/1, &data)); EXPECT_EQ(data[0]->GetTagId(), pullTagId1); ASSERT_EQ(data[0]->getValues().size(), 1); EXPECT_EQ(data[0]->getValues()[0].mValue.int_value, uid2); @@ -142,7 +142,7 @@ TEST(StatsPullerManagerTest, TestPullConfigKeyNoPullerWithUid) { pullerManager->RegisterPullUidProvider(configKey, uidProvider); vector<shared_ptr<LogEvent>> data; - EXPECT_FALSE(pullerManager->Pull(pullTagId2, configKey, /*timestamp =*/1, &data, true)); + EXPECT_FALSE(pullerManager->Pull(pullTagId2, configKey, /*timestamp =*/1, &data)); } } // namespace statsd diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index bb8e7bfd90f4..8e2864c6fba8 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -41,6 +41,7 @@ namespace statsd { namespace { const ConfigKey kConfigKey(0, 12345); +const uint64_t protoHash = 0x1234567890; void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { AStatsEvent* statsEvent = AStatsEvent_obtain(); @@ -75,7 +76,7 @@ TEST(CountMetricProducerTest, TestFirstBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2); + wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2); EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs); EXPECT_EQ(10, countProducer.mCurrentBucketNum); EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs()); @@ -95,7 +96,7 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, bucketStartTimeNs, bucketStartTimeNs); + wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs); // 2 events in bucket 1. LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -158,7 +159,7 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, - bucketStartTimeNs, bucketStartTimeNs); + protoHash, bucketStartTimeNs, bucketStartTimeNs); countProducer.onConditionChanged(true, bucketStartTimeNs); @@ -226,8 +227,8 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/, - {ConditionState::kUnknown}, wizard, bucketStartTimeNs, - bucketStartTimeNs); + {ConditionState::kUnknown}, wizard, protoHash, + bucketStartTimeNs, bucketStartTimeNs); countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); countProducer.flushIfNeededLocked(bucketStartTimeNs + 1); @@ -265,7 +266,7 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard, - bucketStartTimeNs, bucketStartTimeNs); + protoHash, bucketStartTimeNs, bucketStartTimeNs); sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); EXPECT_TRUE(anomalyTracker != nullptr); @@ -332,7 +333,7 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard, - bucketStartTimeNs, bucketStartTimeNs); + protoHash, bucketStartTimeNs, bucketStartTimeNs); // Bucket is flushed yet. LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -397,7 +398,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, bucketStartTimeNs, bucketStartTimeNs); + wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs); sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); @@ -459,7 +460,7 @@ TEST(CountMetricProducerTest, TestOneWeekTimeUnit) { int64_t fiveWeeksNs = 5 * 7 * oneDayNs; CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard, - oneDayNs, fiveWeeksNs); + protoHash, oneDayNs, fiveWeeksNs); int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs; diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp index 05cfa37b0ee1..d1f89775ed6a 100644 --- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp @@ -45,6 +45,7 @@ namespace statsd { namespace { const ConfigKey kConfigKey(0, 12345); +const uint64_t protoHash = 0x1234567890; void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); @@ -71,10 +72,10 @@ TEST(DurationMetricTrackerTest, TestFirstBucket) { FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, 5, + 600 * NS_PER_SEC + NS_PER_SEC / 2); EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs); EXPECT_EQ(10, durationProducer.mCurrentBucketNum); @@ -99,10 +100,10 @@ TEST(DurationMetricTrackerTest, TestNoCondition) { FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); durationProducer.onMatchedLogEvent(1 /* start index*/, event1); durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); @@ -145,7 +146,7 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) { DurationMetricProducer durationProducer( kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown}, 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/, - wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); + wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs); durationProducer.mCondition = ConditionState::kFalse; EXPECT_FALSE(durationProducer.mCondition); @@ -195,7 +196,7 @@ TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) { DurationMetricProducer durationProducer( kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown}, 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/, - wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); + wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs); EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition); EXPECT_FALSE(durationProducer.isConditionSliced()); @@ -238,10 +239,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -301,10 +302,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollo sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -365,10 +366,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor); EXPECT_TRUE(anomalyTracker != nullptr); @@ -411,10 +412,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); int64_t startTimeNs = bucketStartTimeNs + 1; LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -465,10 +466,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextB sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); FieldMatcher dimensions; - DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {}, - 1 /* start index */, 2 /* stop index */, - 3 /* stop_all index */, false /*nesting*/, wizard, - dimensions, bucketStartTimeNs, bucketStartTimeNs); + DurationMetricProducer durationProducer( + kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, + bucketStartTimeNs, bucketStartTimeNs); int64_t startTimeNs = bucketStartTimeNs + 1; LogEvent event1(/*uid=*/0, /*pid=*/0); diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index dfbb9da568b0..4bbbd2cb36ad 100644 --- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp @@ -36,9 +36,11 @@ namespace android { namespace os { namespace statsd { -const ConfigKey kConfigKey(0, 12345); namespace { +const ConfigKey kConfigKey(0, 12345); +const uint64_t protoHash = 0x1234567890; + void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); @@ -66,7 +68,7 @@ TEST(EventMetricProducerTest, TestNoCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, bucketStartTimeNs); + wizard, protoHash, bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); @@ -102,7 +104,8 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/, - {ConditionState::kUnknown}, wizard, bucketStartTimeNs); + {ConditionState::kUnknown}, wizard, protoHash, + bucketStartTimeNs); eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); @@ -157,7 +160,8 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/, - {ConditionState::kUnknown}, wizard, bucketStartTimeNs); + {ConditionState::kUnknown}, wizard, protoHash, + bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 5997bedcdf2d..10606810d806 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -23,7 +23,7 @@ #include "logd/LogEvent.h" #include "metrics_test_helper.h" -#include "src/matchers/SimpleLogMatchingTracker.h" +#include "src/matchers/SimpleAtomMatchingTracker.h" #include "src/metrics/MetricProducer.h" #include "src/stats_log_util.h" #include "stats_event.h" @@ -47,7 +47,7 @@ namespace { const ConfigKey kConfigKey(0, 12345); const int tagId = 1; const int64_t metricId = 123; -const int64_t atomMatcherId = 678; +const uint64_t protoHash = 0x123456789; const int logEventMatcherIndex = 0; const int64_t bucketStartTimeNs = 10 * NS_PER_SEC; const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; @@ -94,19 +94,17 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); - sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ - new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<EventMatcherWizard> eventMatcherWizard = + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); // statsd started long ago. // The metric starts in the middle of the bucket GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, -1, -1, - tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, + pullerManager); gaugeProducer.prepareFirstBucket(); EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs); @@ -127,19 +125,15 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(makeLogEvent(tagId, eventTimeNs + 10, 3, "some value", 11)); @@ -147,8 +141,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { })); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1, - tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, + pullerManager); gaugeProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -217,15 +212,11 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); @@ -301,19 +292,16 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Return(false)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 2)); @@ -321,8 +309,9 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) { })); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1, - tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, + pullerManager); gaugeProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -378,22 +367,19 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(false)); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1, - tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, + pullerManager); gaugeProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -428,30 +414,26 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); int64_t conditionChangeNs = bucketStartTimeNs + 8; sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, conditionChangeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, conditionChangeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs + 10, 100)); return true; })); GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/, - {ConditionState::kUnknown}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + {ConditionState::kUnknown}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); gaugeProducer.onConditionChanged(true, conditionChangeNs); @@ -502,12 +484,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { dim->set_field(tagId); dim->add_child()->set_field(1); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*wizard, query(_, _, _)) @@ -527,18 +505,18 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, sliceConditionChangeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, sliceConditionChangeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs + 10, 1000, 100)); return true; })); GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/, - {ConditionState::kUnknown}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + {ConditionState::kUnknown}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); gaugeProducer.onSlicedConditionMayChange(true, sliceConditionChangeNs); @@ -566,7 +544,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(false)); GaugeMetric metric; @@ -577,16 +555,13 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { gaugeFieldMatcher->set_field(tagId); gaugeFieldMatcher->add_child()->set_field(2); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1, - tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, + pullerManager); gaugeProducer.prepareFirstBucket(); Alert alert; @@ -657,24 +632,20 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 4)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5)); @@ -684,8 +655,8 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) { int triggerId = 5; GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, - triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); @@ -729,31 +700,27 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3); data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 3, 4)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 5)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20); data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 6)); @@ -763,8 +730,8 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) { int triggerId = 5; GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, - triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); @@ -807,18 +774,14 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _)) // Bucket start. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 10)); return true; @@ -826,8 +789,8 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { int triggerId = 5; GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, - triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); gaugeProducer.prepareFirstBucket(); diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 5666501d7d51..b166cc1fe04e 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -22,7 +22,7 @@ #include <vector> #include "metrics_test_helper.h" -#include "src/matchers/SimpleLogMatchingTracker.h" +#include "src/matchers/SimpleAtomMatchingTracker.h" #include "src/metrics/MetricProducer.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" @@ -46,7 +46,7 @@ namespace { const ConfigKey kConfigKey(0, 12345); const int tagId = 1; const int64_t metricId = 123; -const int64_t atomMatcherId = 678; +const uint64_t protoHash = 0x1234567890; const int logEventMatcherIndex = 0; const int64_t bucketStartTimeNs = 10000000000; const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; @@ -58,7 +58,7 @@ const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs; double epsilon = 0.001; static void assertPastBucketValuesSingleKey( - const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets, + const std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>>& mPastBuckets, const std::initializer_list<int>& expectedValuesList, const std::initializer_list<int64_t>& expectedDurationNsList, const std::initializer_list<int64_t>& expectedStartTimeNsList, @@ -80,7 +80,7 @@ static void assertPastBucketValuesSingleKey( ASSERT_EQ(1, mPastBuckets.size()); ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size()); - const vector<ValueBucket>& buckets = mPastBuckets.begin()->second; + const vector<PastValueBucket>& buckets = mPastBuckets.begin()->second; for (int i = 0; i < expectedValues.size(); i++) { EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value) << "Values differ at index " << i; @@ -99,12 +99,8 @@ class ValueMetricProducerTestHelper { public: static sp<ValueMetricProducer> createValueProducerNoConditions( sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -113,8 +109,8 @@ public: sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, - bucketStartTimeNs, bucketStartTimeNs, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer->prepareFirstBucket(); return valueProducer; } @@ -122,12 +118,8 @@ public: static sp<ValueMetricProducer> createValueProducerWithCondition( sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, ConditionState conditionAfterFirstBucketPrepared) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -136,7 +128,7 @@ public: sp<ValueMetricProducer> valueProducer = new ValueMetricProducer( kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard, - logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs, + protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer->prepareFirstBucket(); valueProducer->mCondition = conditionAfterFirstBucketPrepared; @@ -147,12 +139,8 @@ public: sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, vector<int32_t> slicedStateAtoms, unordered_map<int, unordered_map<int, int64_t>> stateGroupMap) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -160,9 +148,9 @@ public: .WillRepeatedly(Return()); sp<ValueMetricProducer> valueProducer = new ValueMetricProducer( - kConfigKey, metric, -1 /* no condition */, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager, {}, - {}, slicedStateAtoms, stateGroupMap); + kConfigKey, metric, -1 /* no condition */, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap); valueProducer->prepareFirstBucket(); return valueProducer; } @@ -172,12 +160,8 @@ public: vector<int32_t> slicedStateAtoms, unordered_map<int, unordered_map<int, int64_t>> stateGroupMap, ConditionState conditionAfterFirstBucketPrepared) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -186,8 +170,9 @@ public: sp<ValueMetricProducer> valueProducer = new ValueMetricProducer( kConfigKey, metric, 0 /* condition tracker index */, {ConditionState::kUnknown}, - wizard, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, + stateGroupMap); valueProducer->prepareFirstBucket(); valueProducer->mCondition = conditionAfterFirstBucketPrepared; return valueProducer; @@ -237,20 +222,16 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); int64_t startTimeBase = 11; - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); // statsd started long ago. // The metric starts in the middle of the bucket ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, -1, - startTimeBase, 22, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + -1, startTimeBase, 22, pullerManager); valueProducer.prepareFirstBucket(); EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10)); @@ -267,20 +248,16 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) { TEST(ValueMetricProducerTest, TestFirstBucket) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); // statsd started long ago. // The metric starts in the middle of the bucket ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, -1, 5, - 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager); + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, + -1, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager); valueProducer.prepareFirstBucket(); EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs); @@ -294,9 +271,9 @@ TEST(ValueMetricProducerTest, TestFirstBucket) { TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); return true; @@ -313,8 +290,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(11, curBaseInfo.base.long_value); @@ -329,8 +307,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(23, curBaseInfo.base.long_value); @@ -347,8 +325,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); @@ -368,19 +346,19 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2; - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Initialize bucket. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1)); return true; })) // Partial bucket. - .WillOnce(Invoke([partialBucketSplitTimeNs]( - int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&, + const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs); data->clear(); data->push_back( @@ -421,30 +399,27 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) { TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); - auto keyValue = atomMatcher.add_field_value_matcher(); - keyValue->set_field(1); - keyValue->set_eq_int(3); + FieldValueMatcher fvm; + fvm.set_field(1); + fvm.set_eq_int(3); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex, {fvm}); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 3, 3)); return true; })); - sp<ValueMetricProducer> valueProducer = new ValueMetricProducer( - kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + sp<ValueMetricProducer> valueProducer = + new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, + protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer->prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -455,8 +430,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(11, curBaseInfo.base.long_value); @@ -484,8 +460,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // the base was reset EXPECT_EQ(true, curBaseInfo.hasBase); @@ -505,7 +481,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { metric.set_use_absolute_value_on_reset(true); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(true)); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric); @@ -518,8 +494,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(11, curBaseInfo.base.long_value); @@ -531,8 +508,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -545,8 +522,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -565,7 +542,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(false)); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric); @@ -578,8 +555,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(11, curBaseInfo.base.long_value); @@ -591,8 +569,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -602,8 +580,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -621,23 +599,23 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // First condition change. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1); // Second condition change. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 130)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 1); // Third condition change. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 180)); @@ -653,8 +631,9 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // startUpdated:false sum:0 start:100 EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -670,8 +649,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(110, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -683,8 +662,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(false, curBaseInfo.hasBase); @@ -698,18 +677,14 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -759,31 +734,27 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) { TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150; EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Return(true)) - .WillOnce(Invoke([partialBucketSplitTimeNs]( - int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&, + const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 120)); return true; })); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -820,22 +791,18 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_split_bucket_for_app_upgrade(false); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(true)); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -854,16 +821,16 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to true time. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs - 100); // Condition change to false time. data->clear(); @@ -900,18 +867,14 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -924,8 +887,9 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -933,7 +897,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(30, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -944,17 +908,13 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, - logEventMatcherIndex, eventMatcherWizard, -1, + protoHash, logEventMatcherIndex, eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); valueProducer.mCondition = ConditionState::kFalse; @@ -974,8 +934,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(20, curInterval.value.long_value); LogEvent event3(/*uid=*/0, /*pid=*/0); @@ -984,7 +944,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(50, curInterval.value.long_value); valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35); @@ -995,7 +955,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(50, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1015,17 +975,13 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, - wizard, logEventMatcherIndex, eventMatcherWizard, + wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); @@ -1081,11 +1037,54 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) { std::ceil(1.0 * event6.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); } +TEST(ValueMetricProducerTest, TestAnomalyDetectionMultipleBucketsSkipped) { + sp<AlarmMonitor> alarmMonitor; + Alert alert; + alert.set_id(101); + alert.set_metric_id(metricId); + alert.set_trigger_if_sum_gt(100); + alert.set_num_buckets(1); + const int32_t refPeriodSec = 3; + alert.set_refractory_period_secs(refPeriodSec); + + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to true time. + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 0)); + return true; + })) + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_EQ(eventTimeNs, + bucket3StartTimeNs + 100); // Condition changed to false time. + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 100, 120)); + return true; + })); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric, + ConditionState::kFalse); + sp<AnomalyTracker> anomalyTracker = valueProducer->addAnomalyTracker(alert, alarmMonitor); + + valueProducer->onConditionChanged(true, bucketStartTimeNs + 1); + + // multiple buckets should be skipped here. + valueProducer->onConditionChanged(false, bucket3StartTimeNs + 100); + + // No alert is fired when multiple buckets are skipped. + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); +} + // Test value metric no condition, the pull on bucket boundary come in time and too late TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Return(true)); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric); @@ -1099,8 +1098,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // startUpdated:true sum:0 start:11 EXPECT_EQ(true, curBaseInfo.hasBase); @@ -1114,8 +1114,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // tartUpdated:false sum:12 EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(23, curBaseInfo.base.long_value); @@ -1131,8 +1131,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // startUpdated:false sum:12 EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); @@ -1164,10 +1164,10 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // condition becomes true .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // First condition change. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); @@ -1175,7 +1175,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { })) // condition becomes false .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1); // Second condition change. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120)); @@ -1190,8 +1190,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -1199,8 +1200,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { // pull on bucket boundary come late, condition change happens before it valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); EXPECT_EQ(false, curBaseInfo.hasBase); @@ -1213,8 +1214,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); } @@ -1227,10 +1228,10 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // condition becomes true .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); @@ -1238,7 +1239,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { })) // condition becomes false .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120)); @@ -1246,7 +1247,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { })) // condition becomes true again .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 25); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130)); @@ -1262,8 +1263,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // startUpdated:false sum:0 start:100 EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -1275,8 +1277,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -1284,8 +1286,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25); assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(130, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -1296,8 +1298,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1317,18 +1319,14 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::MIN); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1341,7 +1339,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1349,7 +1347,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1361,18 +1359,14 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::MAX); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1382,7 +1376,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1392,7 +1386,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(20, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1404,18 +1398,14 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::AVG); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1427,7 +1417,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval; - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(1, curInterval.sampleSize); @@ -1436,7 +1426,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(25, curInterval.value.long_value); EXPECT_EQ(2, curInterval.sampleSize); @@ -1452,18 +1442,14 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::SUM); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1475,7 +1461,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1483,7 +1469,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(25, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1496,18 +1482,14 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { metric.set_aggregation_type(ValueMetric::MIN); metric.set_use_diff(true); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1517,8 +1499,9 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -1529,7 +1512,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(5, curInterval.value.long_value); @@ -1539,8 +1522,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1550,8 +1533,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1568,18 +1551,14 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { metric.set_aggregation_type(ValueMetric::MIN); metric.set_use_diff(true); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs, - pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, -1, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); @@ -1592,12 +1571,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(20, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -1606,12 +1586,12 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(5, curInterval.value.long_value); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(2, curInterval.value.long_value); @@ -1621,14 +1601,14 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(25, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1638,13 +1618,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; - curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; + curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(29, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1677,9 +1657,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { metric.set_use_zero_default_base(true); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3)); return true; @@ -1690,9 +1670,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); auto iter = valueProducer->mCurrentSlicedBucket.begin(); - auto& interval1 = iter->second[0]; + auto& interval1 = iter->second.intervals[0]; auto iterBase = valueProducer->mCurrentBaseInfo.begin(); - auto& baseInfo1 = iterBase->second[0]; + auto& baseInfo1 = iterBase->second.baseInfos[0]; EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo1.hasBase); EXPECT_EQ(3, baseInfo1.base.long_value); @@ -1726,8 +1706,8 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { } EXPECT_TRUE(it != iter); EXPECT_TRUE(itBase != iterBase); - auto& interval2 = it->second[0]; - auto& baseInfo2 = itBase->second[0]; + auto& interval2 = it->second.intervals[0]; + auto& baseInfo2 = itBase->second.baseInfos[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(4, baseInfo2.base.long_value); @@ -1753,9 +1733,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { metric.set_use_zero_default_base(true); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3)); return true; @@ -1766,9 +1746,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); const auto& it = valueProducer->mCurrentSlicedBucket.begin(); - ValueMetricProducer::Interval& interval1 = it->second[0]; + ValueMetricProducer::Interval& interval1 = it->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo1 = - valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0]; + valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()) + ->second.baseInfos[0]; EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo1.hasBase); EXPECT_EQ(3, baseInfo1.base.long_value); @@ -1795,9 +1776,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { } } EXPECT_TRUE(it2 != it); - ValueMetricProducer::Interval& interval2 = it2->second[0]; + ValueMetricProducer::Interval& interval2 = it2->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo2 = - valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0]; + valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat()) + ->second.baseInfos[0]; EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(4, baseInfo2.base.long_value); @@ -1826,14 +1808,16 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { // Get new references now that entries have been deleted from the map const auto& it3 = valueProducer->mCurrentSlicedBucket.begin(); const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin()); - ASSERT_EQ(it3->second.size(), 1); - ASSERT_EQ(it4->second.size(), 1); - ValueMetricProducer::Interval& interval3 = it3->second[0]; - ValueMetricProducer::Interval& interval4 = it4->second[0]; + ASSERT_EQ(it3->second.intervals.size(), 1); + ASSERT_EQ(it4->second.intervals.size(), 1); + ValueMetricProducer::Interval& interval3 = it3->second.intervals[0]; + ValueMetricProducer::Interval& interval4 = it4->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo3 = - valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0]; + valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat()) + ->second.baseInfos[0]; ValueMetricProducer::BaseInfo& baseInfo4 = - valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())->second[0]; + valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat()) + ->second.baseInfos[0]; EXPECT_EQ(true, baseInfo3.hasBase); EXPECT_EQ(5, baseInfo3.base.long_value); @@ -1858,9 +1842,9 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { metric.mutable_dimensions_in_what()->add_child()->set_field(1); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3)); return true; @@ -1871,9 +1855,9 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); auto iter = valueProducer->mCurrentSlicedBucket.begin(); - auto& interval1 = iter->second[0]; + auto& interval1 = iter->second.intervals[0]; auto iterBase = valueProducer->mCurrentBaseInfo.begin(); - auto& baseInfo1 = iterBase->second[0]; + auto& baseInfo1 = iterBase->second.baseInfos[0]; EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo1.hasBase); EXPECT_EQ(3, baseInfo1.base.long_value); @@ -1909,8 +1893,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { } EXPECT_TRUE(it != iter); EXPECT_TRUE(itBase != iterBase); - auto interval2 = it->second[0]; - auto baseInfo2 = itBase->second[0]; + auto interval2 = it->second.intervals[0]; + auto baseInfo2 = itBase->second.baseInfos[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(4, baseInfo2.base.long_value); @@ -1923,8 +1907,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); // Only one interval left. One was trimmed. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0]; + interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(5, baseInfo2.base.long_value); @@ -1937,8 +1921,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs); - interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0]; + interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(14, baseInfo2.base.long_value); EXPECT_EQ(false, interval2.hasValue); @@ -1961,9 +1945,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); // Used by onConditionChanged. - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); return true; @@ -1977,8 +1961,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo& curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -1995,9 +1980,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // Condition change to true. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); @@ -2014,8 +1999,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo& curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -2034,16 +2020,16 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50)); return false; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to false. data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100)); @@ -2064,8 +2050,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) { valueProducer->onConditionChanged(false, bucketStartTimeNs + 1); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(false, valueProducer->mHasGlobalBase); @@ -2077,9 +2064,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) { metric.set_max_pull_delay_sec(0); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 120)); return true; @@ -2097,19 +2084,15 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) { TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return()); ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, - logEventMatcherIndex, eventMatcherWizard, tagId, + protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, bucket2StartTimeNs, bucket2StartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); valueProducer.mCondition = ConditionState::kFalse; @@ -2124,9 +2107,9 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100)); return true; @@ -2141,8 +2124,9 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) { valueProducer->mHasGlobalBase = true; ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -2156,12 +2140,12 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First onConditionChanged .WillOnce(Return(false)) // Second onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130)); @@ -2194,8 +2178,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed // Contains base from last pull which was successful. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -2233,10 +2218,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) { metric.set_condition(StringToId("SCREEN_ON")); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 2, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 2, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { for (int i = 0; i < 2000; i++) { data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i)); } @@ -2290,10 +2275,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120)); @@ -2301,7 +2286,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) })) // Second onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130)); @@ -2332,8 +2317,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) // Contains base from last pull which was successful. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -2369,10 +2355,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120)); @@ -2380,7 +2366,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) { })) // Second onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130)); @@ -2411,8 +2397,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) { // Last pull failed so base has been reset. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(false, valueProducer->mHasGlobalBase); @@ -2442,10 +2429,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) { TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) // Start bucket. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); return true; @@ -2475,17 +2462,17 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); return true; @@ -2498,8 +2485,9 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { valueProducer->onConditionChanged(true, bucketStartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(true, valueProducer->mHasGlobalBase); @@ -2507,8 +2495,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { // Empty pull. valueProducer->onConditionChanged(false, bucketStartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(false, valueProducer->mHasGlobalBase); @@ -2518,24 +2506,24 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 11); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 2)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 12); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 5)); @@ -2551,8 +2539,9 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { valueProducer->onConditionChanged(true, bucketStartTimeNs + 12); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(true, valueProducer->mHasGlobalBase); @@ -2562,8 +2551,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { allData.clear(); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; // Data is empty, base should be reset. EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(5, curBaseInfo.base.long_value); @@ -2582,10 +2571,10 @@ TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) { metric.set_condition(StringToId("SCREEN_ON")); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _)) // First onConditionChanged .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); return true; @@ -2608,14 +2597,14 @@ TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) { ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size()); auto iterator = valueProducer->mCurrentSlicedBucket.begin(); auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin(); - EXPECT_EQ(true, baseInfoIter->second[0].hasBase); - EXPECT_EQ(2, baseInfoIter->second[0].base.long_value); - EXPECT_EQ(false, iterator->second[0].hasValue); + EXPECT_EQ(true, baseInfoIter->second.baseInfos[0].hasBase); + EXPECT_EQ(2, baseInfoIter->second.baseInfos[0].base.long_value); + EXPECT_EQ(false, iterator->second.intervals[0].hasValue); iterator++; baseInfoIter++; - EXPECT_EQ(false, baseInfoIter->second[0].hasBase); - EXPECT_EQ(1, baseInfoIter->second[0].base.long_value); - EXPECT_EQ(false, iterator->second[0].hasValue); + EXPECT_EQ(false, baseInfoIter->second.baseInfos[0].hasBase); + EXPECT_EQ(1, baseInfoIter->second.baseInfos[0].base.long_value); + EXPECT_EQ(false, iterator->second.intervals[0].hasValue); EXPECT_EQ(true, valueProducer->mHasGlobalBase); } @@ -2625,19 +2614,19 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketI sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); int64_t partialBucketSplitTimeNs = bucketStartTimeNs + bucketSizeNs / 2; - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Initialization. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); return true; })) // notifyAppUpgrade. - .WillOnce(Invoke([partialBucketSplitTimeNs]( - int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&, + const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10)); @@ -2681,10 +2670,10 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketI TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Second onConditionChanged. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 5)); @@ -2692,7 +2681,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) { })) // Third onConditionChanged. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 10, 7)); @@ -2714,8 +2703,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) { valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(5, curBaseInfo.base.long_value); EXPECT_EQ(false, curInterval.hasValue); @@ -2752,10 +2741,10 @@ TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) // Initialization. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); return true; @@ -2782,19 +2771,19 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestBucketBoundariesOnPartialBucke int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2; sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Initialization. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); return true; })) // notifyAppUpgrade. - .WillOnce(Invoke([partialBucketSplitTimeNs]( - int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&, + const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10)); @@ -2822,10 +2811,10 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First on condition changed. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); @@ -2833,7 +2822,7 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) { })) // Second on condition changed. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); @@ -2849,8 +2838,8 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) { valueProducer->onConditionChanged(false, bucketStartTimeNs + 12); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(2, curInterval.value.long_value); @@ -2867,10 +2856,10 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First condition change. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1)); @@ -2878,7 +2867,7 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) { })) // 2nd condition change. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 8); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1)); @@ -2886,7 +2875,7 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) { })) // 3rd condition change. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1)); @@ -2920,29 +2909,25 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) { TEST(ValueMetricProducerTest, TestPullNeededFastDump) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) // Initial pull. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1)); return true; })); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); ProtoOutputStream output; @@ -2958,29 +2943,25 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) { TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _)) // Initial pull. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1)); return true; })); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); vector<shared_ptr<LogEvent>> allData; @@ -3002,28 +2983,24 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) { TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Initial pull. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1)); return true; })) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back( @@ -3031,9 +3008,9 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) { return true; })); - ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex, - eventMatcherWizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); valueProducer.prepareFirstBucket(); ProtoOutputStream output; @@ -3069,10 +3046,10 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges metric.set_use_diff(false); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // condition becomes true .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10)); @@ -3080,7 +3057,7 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges })) // condition becomes false .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 20)); @@ -3095,8 +3072,9 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(20, curInterval.value.long_value); @@ -3108,8 +3086,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; - curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); } @@ -3119,10 +3097,10 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) { metric.set_use_diff(false); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _)) // condition becomes true .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10)); return true; @@ -3141,8 +3119,9 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; - ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; + ValueMetricProducer::BaseInfo curBaseInfo = + valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); } @@ -3170,10 +3149,10 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure) { metric.set_use_diff(false); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // condition becomes true .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10)); @@ -3210,10 +3189,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequeste ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 20, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 20, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 10)); return true; @@ -3256,10 +3235,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWron ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 50, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 50, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10)); return true; @@ -3314,10 +3293,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWro ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10)); @@ -3325,7 +3304,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWro })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 100); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 100, 15)); @@ -3380,10 +3359,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown) ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10)); @@ -3391,7 +3370,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown) })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10000); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 100, 15)); @@ -3436,10 +3415,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10)); @@ -3486,10 +3465,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSki ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10)); @@ -3497,7 +3476,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSki })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket4StartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1000, 15)); @@ -3560,10 +3539,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { metric.set_min_bucket_size_nanos(10000000000); // 10 seconds sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10)); @@ -3571,7 +3550,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 9000000); data->clear(); data->push_back( @@ -3651,10 +3630,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC); data->clear(); data->push_back(CreateRepeatedValueLogEvent( @@ -3663,7 +3642,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) { })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 15 * NS_PER_SEC); data->clear(); data->push_back(CreateRepeatedValueLogEvent( @@ -3740,10 +3719,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBefor ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10)); @@ -3751,7 +3730,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBefor })) // App Update. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1000); data->clear(); data->push_back( @@ -3806,10 +3785,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _)) // Condition change to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10)); return true; @@ -3857,10 +3836,10 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // First condition change event. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); for (int i = 0; i < 2000; i++) { data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i)); @@ -3877,7 +3856,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) { .WillOnce(Return(false)) .WillOnce(Return(false)) .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 220); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 220, 10)); @@ -3976,10 +3955,10 @@ TEST(ValueMetricProducerTest, TestSlicedState) { // Set up ValueMetricProducer. ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE"); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // ValueMetricProducer initialized. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); @@ -3987,7 +3966,7 @@ TEST(ValueMetricProducerTest, TestSlicedState) { })) // Screen state change to ON. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5)); @@ -3995,7 +3974,7 @@ TEST(ValueMetricProducerTest, TestSlicedState) { })) // Screen state change to OFF. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 9)); @@ -4003,7 +3982,7 @@ TEST(ValueMetricProducerTest, TestSlicedState) { })) // Screen state change to ON. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21)); @@ -4011,7 +3990,7 @@ TEST(ValueMetricProducerTest, TestSlicedState) { })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30)); @@ -4034,18 +4013,18 @@ TEST(ValueMetricProducerTest, TestSlicedState) { // Base for dimension key {} auto it = valueProducer->mCurrentSlicedBucket.begin(); auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(3, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, kStateUnknown} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after screen state change kStateUnknown->ON. auto screenEvent = CreateScreenStateChangedEvent( @@ -4055,19 +4034,19 @@ TEST(ValueMetricProducerTest, TestSlicedState) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(5, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, kStateUnknown} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change ON->OFF. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, @@ -4077,26 +4056,26 @@ TEST(ValueMetricProducerTest, TestSlicedState) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(9, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, ON} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change OFF->ON. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15, @@ -4106,35 +4085,35 @@ TEST(ValueMetricProducerTest, TestSlicedState) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(21, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, OFF} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(12, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(12, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, ON} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; @@ -4178,10 +4157,10 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Set up ValueMetricProducer. ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE_ONOFF"); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // ValueMetricProducer initialized. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3)); @@ -4189,7 +4168,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { })) // Screen state change to ON. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5)); @@ -4203,7 +4182,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Screen state change to OFF. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21)); @@ -4211,7 +4190,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { })) // Dump report requested. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50); data->clear(); data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30)); @@ -4245,18 +4224,18 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Base for dimension key {} auto it = valueProducer->mCurrentSlicedBucket.begin(); auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(3, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, {kStateUnknown}} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after screen state change kStateUnknown->ON. auto screenEvent = CreateScreenStateChangedEvent( @@ -4266,19 +4245,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(5, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(screenOnGroup.group_id(), - itBase->second[0].currentState.getValues()[0].mValue.long_value); + itBase->second.currentState.getValues()[0].mValue.long_value); // Value for dimension, state key {{}, kStateUnknown} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change ON->VR. // Both ON and VR are in the same state group, so the base should not change. @@ -4289,19 +4268,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(5, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(screenOnGroup.group_id(), - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, kStateUnknown} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change VR->ON. // Both ON and VR are in the same state group, so the base should not change. @@ -4312,19 +4291,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(5, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(screenOnGroup.group_id(), - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, kStateUnknown} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change VR->OFF. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15, @@ -4334,27 +4313,27 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { // Base for dimension key {} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(21, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(screenOffGroup.group_id(), - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{}, ON GROUP} EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(screenOnGroup.group_id(), it->first.getStateValuesKey().getValues()[0].mValue.long_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(16, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(16, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; @@ -4408,10 +4387,10 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */}); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // ValueMetricProducer initialized. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs); data->clear(); data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 2 /*uid*/, 7)); @@ -4420,7 +4399,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { })) // Uid 1 process state change from kStateUnknown -> Foreground .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20); data->clear(); data->push_back( @@ -4433,7 +4412,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { })) // Uid 2 process state change from kStateUnknown -> Background .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40); data->clear(); data->push_back( @@ -4446,7 +4425,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { })) // Uid 1 process state change from Foreground -> Background .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20); data->clear(); data->push_back( @@ -4459,7 +4438,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { })) // Uid 1 process state change from Background -> Foreground .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40); data->clear(); data->push_back( @@ -4472,7 +4451,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { })) // Dump report pull. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50); data->clear(); data->push_back( @@ -4497,35 +4476,35 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { // Base for dimension key {uid 1}. auto it = valueProducer->mCurrentSlicedBucket.begin(); auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(3, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{uid 1}, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 2} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(7, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for dimension, state key {{uid 2}, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change kStateUnknown -> Foreground. auto uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4535,36 +4514,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { // Base for dimension key {uid 1}. it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(6, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 1, kStateUnknown}. ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Base for dimension key {uid 2} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(7, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 2, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 2 process state change kStateUnknown -> Background. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4574,36 +4553,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { // Base for dimension key {uid 1}. it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(6, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 1, kStateUnknown}. ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Base for dimension key {uid 2} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(9, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 2, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Pull at end of first bucket. vector<shared_ptr<LogEvent>> allData; @@ -4620,36 +4599,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { it = valueProducer->mCurrentSlicedBucket.begin(); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(15, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 2, BACKGROUND}. ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(10, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(10, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 1, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* kStateTracker::kUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, FOREGROUND} it++; @@ -4658,7 +4637,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 2, kStateUnknown} it++; @@ -4667,7 +4646,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* kStateTracker::kUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change from Foreground -> Background. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4680,35 +4659,35 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { // Base for dimension key {uid 2}. it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(15, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 2, BACKGROUND}. ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(13, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(13, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 1, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, FOREGROUND} it++; ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); @@ -4716,8 +4695,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Value for key {uid 2, kStateUnknown} it++; ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); @@ -4725,7 +4704,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change Background->Foreground. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4737,36 +4716,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { // Base for dimension key {uid 2} it = valueProducer->mCurrentSlicedBucket.begin(); itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(15, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 2, BACKGROUND} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(17, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(17, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {uid 1, kStateUnknown} ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, BACKGROUND} it++; @@ -4775,8 +4754,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for key {uid 1, FOREGROUND} it++; @@ -4785,8 +4764,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Value for key {uid 2, kStateUnknown} it++; @@ -4852,10 +4831,10 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState( "BATTERY_SAVER_MODE_STATE"); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) // Condition changed to true. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC); data->clear(); data->push_back( @@ -4864,7 +4843,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { })) // Battery saver mode state changed to OFF. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC); data->clear(); data->push_back( @@ -4873,7 +4852,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { })) // Condition changed to false. .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC); data->clear(); data->push_back(CreateRepeatedValueLogEvent( @@ -4907,23 +4886,23 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC); // Base for dimension key {} ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); - std::unordered_map<HashableDimensionKey, std::vector<ValueMetricProducer::BaseInfo>>::iterator + std::unordered_map<HashableDimensionKey, ValueMetricProducer::DimensionsInWhatInfo>::iterator itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(3, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::ON, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {{}, -1} ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator - it = valueProducer->mCurrentSlicedBucket.begin(); + std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it = + valueProducer->mCurrentSlicedBucket.begin(); EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /*StateTracker::kUnknown*/, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after battery saver mode OFF event. unique_ptr<LogEvent> batterySaverOffEvent = @@ -4932,12 +4911,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { // Base for dimension key {} ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(5, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::OFF, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {{}, ON} ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size()); it = valueProducer->mCurrentSlicedBucket.begin(); @@ -4945,8 +4924,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Pull at end of first bucket. vector<shared_ptr<LogEvent>> allData; @@ -4959,23 +4938,23 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { // Base for dimension key {} ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); - EXPECT_TRUE(itBase->second[0].hasBase); - EXPECT_EQ(11, itBase->second[0].base.long_value); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_TRUE(itBase->second.baseInfos[0].hasBase); + EXPECT_EQ(11, itBase->second.baseInfos[0].base.long_value); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::OFF, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Bucket 2 status after condition change to false. valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC); // Base for dimension key {} ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); - EXPECT_FALSE(itBase->second[0].hasBase); - EXPECT_TRUE(itBase->second[0].hasCurrentState); - ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_FALSE(itBase->second.baseInfos[0].hasBase); + EXPECT_TRUE(itBase->second.hasCurrentState); + ASSERT_EQ(1, itBase->second.currentState.getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::OFF, - itBase->second[0].currentState.getValues()[0].mValue.int_value); + itBase->second.currentState.getValues()[0].mValue.int_value); // Value for key {{}, OFF} ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size()); it = valueProducer->mCurrentSlicedBucket.begin(); @@ -4983,8 +4962,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::OFF, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h index eeb38a4644fd..39232c194ada 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.h +++ b/cmds/statsd/tests/metrics/metrics_test_helper.h @@ -38,11 +38,10 @@ public: int64_t nextPulltimeNs, int64_t intervalNs)); MOCK_METHOD3(UnRegisterReceiver, void(int tagId, const ConfigKey& key, wp<PullDataReceiver> receiver)); - MOCK_METHOD5(Pull, bool(const int pullCode, const ConfigKey& key, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids)); - MOCK_METHOD5(Pull, - bool(const int pullCode, const vector<int32_t>& uids, const int64_t eventTimeNs, - vector<std::shared_ptr<LogEvent>>* data, bool useUids)); + MOCK_METHOD4(Pull, bool(const int pullCode, const ConfigKey& key, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data)); + MOCK_METHOD4(Pull, bool(const int pullCode, const vector<int32_t>& uids, + const int64_t eventTimeNs, vector<std::shared_ptr<LogEvent>>* data)); MOCK_METHOD2(RegisterPullUidProvider, void(const ConfigKey& configKey, wp<PullUidProvider> provider)); MOCK_METHOD2(UnregisterPullUidProvider, diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp new file mode 100644 index 000000000000..843d836a2c0b --- /dev/null +++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp @@ -0,0 +1,897 @@ +// 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. + +#include "src/metrics/parsing_utils/config_update_utils.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <private/android_filesystem_config.h> +#include <stdio.h> + +#include <set> +#include <unordered_map> +#include <vector> + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "src/condition/CombinationConditionTracker.h" +#include "src/condition/SimpleConditionTracker.h" +#include "src/matchers/CombinationAtomMatchingTracker.h" +#include "src/metrics/parsing_utils/metrics_manager_util.h" +#include "tests/statsd_test_util.h" + +using namespace testing; +using android::sp; +using android::os::statsd::Predicate; +using std::map; +using std::set; +using std::unordered_map; +using std::vector; + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +namespace { + +ConfigKey key(123, 456); +const int64_t timeBaseNs = 1000; +sp<UidMap> uidMap = new UidMap(); +sp<StatsPullerManager> pullerManager = new StatsPullerManager(); +sp<AlarmMonitor> anomalyAlarmMonitor; +sp<AlarmMonitor> periodicAlarmMonitor; +set<int> allTagIds; +vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers; +unordered_map<int64_t, int> oldAtomMatchingTrackerMap; +vector<sp<ConditionTracker>> oldConditionTrackers; +unordered_map<int64_t, int> oldConditionTrackerMap; +vector<sp<MetricProducer>> oldMetricProducers; +unordered_map<int64_t, int> oldMetricProducerMap; +std::vector<sp<AnomalyTracker>> oldAnomalyTrackers; +std::vector<sp<AlarmTracker>> oldAlarmTrackers; +unordered_map<int, std::vector<int>> conditionToMetricMap; +unordered_map<int, std::vector<int>> trackerToMetricMap; +unordered_map<int, std::vector<int>> trackerToConditionMap; +unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; +unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; +unordered_map<int64_t, int> alertTrackerMap; +vector<int> metricsWithActivation; +map<int64_t, uint64_t> oldStateHashes; +std::set<int64_t> noReportMetricIds; + +class ConfigUpdateTest : public ::testing::Test { +public: + ConfigUpdateTest() { + } + + void SetUp() override { + allTagIds.clear(); + oldAtomMatchingTrackers.clear(); + oldAtomMatchingTrackerMap.clear(); + oldConditionTrackers.clear(); + oldConditionTrackerMap.clear(); + oldMetricProducers.clear(); + oldMetricProducerMap.clear(); + oldAnomalyTrackers.clear(); + oldAlarmTrackers.clear(); + conditionToMetricMap.clear(); + trackerToMetricMap.clear(); + trackerToConditionMap.clear(); + activationAtomTrackerToMetricMap.clear(); + deactivationAtomTrackerToMetricMap.clear(); + alertTrackerMap.clear(); + metricsWithActivation.clear(); + oldStateHashes.clear(); + noReportMetricIds.clear(); + } +}; + +bool initConfig(const StatsdConfig& config) { + return initStatsdConfig( + key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap, + oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap, + oldAnomalyTrackers, oldAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + oldStateHashes, noReportMetricIds); +} + +} // anonymous namespace + +TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + int64_t matcherId = matcher.id(); + *config.add_atom_matcher() = matcher; + + // Create an initial config. + EXPECT_TRUE(initConfig(config)); + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + newAtomMatchingTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(config, 0, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + *config.add_atom_matcher() = matcher; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + // Same id, different atom, so should be replaced. + AtomMatcher newMatcher = CreateSimpleAtomMatcher("TEST", /*atom=*/11); + int64_t matcherId = newMatcher.id(); + EXPECT_EQ(matcherId, matcher.id()); + *newConfig.add_atom_matcher() = newMatcher; + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + newAtomMatchingTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + *config.add_atom_matcher() = matcher; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + // Different id, so should be a new matcher. + AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10); + int64_t matcherId = newMatcher.id(); + EXPECT_NE(matcherId, matcher.id()); + *newConfig.add_atom_matcher() = newMatcher; + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + newAtomMatchingTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + // Same matchers, different order, all should be preserved. + *newConfig.add_atom_matcher() = matcher2; + newAtomMatchingTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newAtomMatchingTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newAtomMatchingTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. It should recurse the two child matchers and preserve all 3. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE); + EXPECT_EQ(matchersToUpdate[1], UPDATE_PRESERVE); + EXPECT_EQ(matchersToUpdate[2], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherReplace) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + // Change the logical operation of the combination matcher, causing a replacement. + matcher3.mutable_combination()->set_operation(LogicalOperation::AND); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + *newConfig.add_atom_matcher() = matcher2; + newAtomMatchingTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newAtomMatchingTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newAtomMatchingTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. The simple matchers should not be evaluated. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_UNKNOWN); + EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE); + EXPECT_EQ(matchersToUpdate[2], UPDATE_UNKNOWN); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherDepsChange) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + // Change a dependency of matcher 3. + matcher2.mutable_simple_atom_matcher()->set_atom_id(12); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + *newConfig.add_atom_matcher() = matcher2; + newAtomMatchingTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newAtomMatchingTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newAtomMatchingTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + // Matcher 2 and matcher3 must be reevaluated. Matcher 1 might, but does not need to be. + EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestUpdateMatchers) { + StatsdConfig config; + // Will be preserved. + AtomMatcher simple1 = CreateSimpleAtomMatcher("SIMPLE1", /*atom=*/10); + int64_t simple1Id = simple1.id(); + *config.add_atom_matcher() = simple1; + + // Will be replaced. + AtomMatcher simple2 = CreateSimpleAtomMatcher("SIMPLE2", /*atom=*/11); + *config.add_atom_matcher() = simple2; + int64_t simple2Id = simple2.id(); + + // Will be removed. + AtomMatcher simple3 = CreateSimpleAtomMatcher("SIMPLE3", /*atom=*/12); + *config.add_atom_matcher() = simple3; + int64_t simple3Id = simple3.id(); + + // Will be preserved. + AtomMatcher combination1; + combination1.set_id(StringToId("combination1")); + AtomMatcher_Combination* combination = combination1.mutable_combination(); + combination->set_operation(LogicalOperation::NOT); + combination->add_matcher(simple1Id); + int64_t combination1Id = combination1.id(); + *config.add_atom_matcher() = combination1; + + // Will be replaced since it depends on simple2. + AtomMatcher combination2; + combination2.set_id(StringToId("combination2")); + combination = combination2.mutable_combination(); + combination->set_operation(LogicalOperation::AND); + combination->add_matcher(simple1Id); + combination->add_matcher(simple2Id); + int64_t combination2Id = combination2.id(); + *config.add_atom_matcher() = combination2; + + EXPECT_TRUE(initConfig(config)); + + // Change simple2, causing simple2 and combination2 to be replaced. + simple2.mutable_simple_atom_matcher()->set_atom_id(111); + + // 2 new matchers: simple4 and combination3: + AtomMatcher simple4 = CreateSimpleAtomMatcher("SIMPLE4", /*atom=*/13); + int64_t simple4Id = simple4.id(); + + AtomMatcher combination3; + combination3.set_id(StringToId("combination3")); + combination = combination3.mutable_combination(); + combination->set_operation(LogicalOperation::AND); + combination->add_matcher(simple4Id); + combination->add_matcher(simple2Id); + int64_t combination3Id = combination3.id(); + + StatsdConfig newConfig; + *newConfig.add_atom_matcher() = combination3; + *newConfig.add_atom_matcher() = simple2; + *newConfig.add_atom_matcher() = combination2; + *newConfig.add_atom_matcher() = simple1; + *newConfig.add_atom_matcher() = simple4; + *newConfig.add_atom_matcher() = combination1; + + set<int> newTagIds; + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers; + set<int64_t> replacedMatchers; + EXPECT_TRUE(updateAtomMatchingTrackers( + newConfig, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds, + newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers)); + + ASSERT_EQ(newTagIds.size(), 3); + EXPECT_EQ(newTagIds.count(10), 1); + EXPECT_EQ(newTagIds.count(111), 1); + EXPECT_EQ(newTagIds.count(13), 1); + + ASSERT_EQ(newAtomMatchingTrackerMap.size(), 6); + EXPECT_EQ(newAtomMatchingTrackerMap.at(combination3Id), 0); + EXPECT_EQ(newAtomMatchingTrackerMap.at(simple2Id), 1); + EXPECT_EQ(newAtomMatchingTrackerMap.at(combination2Id), 2); + EXPECT_EQ(newAtomMatchingTrackerMap.at(simple1Id), 3); + EXPECT_EQ(newAtomMatchingTrackerMap.at(simple4Id), 4); + EXPECT_EQ(newAtomMatchingTrackerMap.at(combination1Id), 5); + + ASSERT_EQ(newAtomMatchingTrackers.size(), 6); + // Make sure all atom matchers are initialized: + for (const sp<AtomMatchingTracker>& tracker : newAtomMatchingTrackers) { + EXPECT_TRUE(tracker->mInitialized); + } + // Make sure preserved atom matchers are the same. + EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple1Id)], + newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple1Id)]); + EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination1Id)], + newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination1Id)]); + // Make sure replaced matchers are different. + EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple2Id)], + newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple2Id)]); + EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination2Id)], + newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination2Id)]); + + // Validation, make sure the matchers have the proper ids/indices. Could do more checks here. + EXPECT_EQ(newAtomMatchingTrackers[0]->getId(), combination3Id); + EXPECT_EQ(newAtomMatchingTrackers[0]->mIndex, 0); + EXPECT_EQ(newAtomMatchingTrackers[1]->getId(), simple2Id); + EXPECT_EQ(newAtomMatchingTrackers[1]->mIndex, 1); + EXPECT_EQ(newAtomMatchingTrackers[2]->getId(), combination2Id); + EXPECT_EQ(newAtomMatchingTrackers[2]->mIndex, 2); + EXPECT_EQ(newAtomMatchingTrackers[3]->getId(), simple1Id); + EXPECT_EQ(newAtomMatchingTrackers[3]->mIndex, 3); + EXPECT_EQ(newAtomMatchingTrackers[4]->getId(), simple4Id); + EXPECT_EQ(newAtomMatchingTrackers[4]->mIndex, 4); + EXPECT_EQ(newAtomMatchingTrackers[5]->getId(), combination1Id); + EXPECT_EQ(newAtomMatchingTrackers[5]->mIndex, 5); + + // Verify child indices of Combination Matchers are correct. + CombinationAtomMatchingTracker* combinationTracker1 = + static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[5].get()); + vector<int>* childMatchers = &combinationTracker1->mChildren; + EXPECT_EQ(childMatchers->size(), 1); + EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end()); + + CombinationAtomMatchingTracker* combinationTracker2 = + static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[2].get()); + childMatchers = &combinationTracker2->mChildren; + EXPECT_EQ(childMatchers->size(), 2); + EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end()); + EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end()); + + CombinationAtomMatchingTracker* combinationTracker3 = + static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[0].get()); + childMatchers = &combinationTracker3->mChildren; + EXPECT_EQ(childMatchers->size(), 2); + EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end()); + EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end()); + + // Expect replacedMatchers to have simple2 and combination2 + ASSERT_EQ(replacedMatchers.size(), 2); + EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end()); + EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end()); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + // Create an initial config. + EXPECT_TRUE(initConfig(config)); + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + EXPECT_TRUE(initConfig(config)); + + // Modify the predicate. + config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true); + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + int64_t startMatcherId = startMatcher.id(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + EXPECT_TRUE(initConfig(config)); + + // Start matcher was replaced. + set<int64_t> replacedMatchers; + replacedMatchers.insert(startMatcherId); + + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + // Same predicates, different order + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. It should recurse the two child predicates and preserve all 3. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE); + EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + // Changing the logical operation changes the predicate definition, so it should be replaced. + combination1.mutable_combination()->set_operation(LogicalOperation::OR); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. The simple conditions should not be evaluated. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN); + EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN); +} + +TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + simple2.mutable_simple_predicate()->set_count_nesting(false); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. Simple2 and combination1 must be evaluated. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestUpdateConditions) { + StatsdConfig config; + + // Add atom matchers. These are mostly needed for initStatsdConfig + AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher(); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher(); + int64_t matcher2Id = matcher2.id(); + *config.add_atom_matcher() = matcher2; + + AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher(); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher(); + int64_t matcher4Id = matcher4.id(); + *config.add_atom_matcher() = matcher4; + + AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher(); + int64_t matcher5Id = matcher5.id(); + *config.add_atom_matcher() = matcher5; + + AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher(); + int64_t matcher6Id = matcher6.id(); + *config.add_atom_matcher() = matcher6; + + // Add the predicates. + // Will be preserved. + Predicate simple1 = CreateScreenIsOnPredicate(); + int64_t simple1Id = simple1.id(); + *config.add_predicate() = simple1; + + // Will be preserved. + Predicate simple2 = CreateScheduledJobPredicate(); + int64_t simple2Id = simple2.id(); + *config.add_predicate() = simple2; + + // Will be replaced. + Predicate simple3 = CreateBatterySaverModePredicate(); + int64_t simple3Id = simple3.id(); + *config.add_predicate() = simple3; + + // Will be preserved + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + combination1.mutable_combination()->set_operation(LogicalOperation::AND); + combination1.mutable_combination()->add_predicate(simple1Id); + combination1.mutable_combination()->add_predicate(simple2Id); + int64_t combination1Id = combination1.id(); + *config.add_predicate() = combination1; + + // Will be replaced since simple3 will be replaced. + Predicate combination2; + combination2.set_id(StringToId("COMBINATION2")); + combination2.mutable_combination()->set_operation(LogicalOperation::OR); + combination2.mutable_combination()->add_predicate(simple1Id); + combination2.mutable_combination()->add_predicate(simple3Id); + int64_t combination2Id = combination2.id(); + *config.add_predicate() = combination2; + + // Will be removed. + Predicate combination3; + combination3.set_id(StringToId("COMBINATION3")); + combination3.mutable_combination()->set_operation(LogicalOperation::NOT); + combination3.mutable_combination()->add_predicate(simple2Id); + int64_t combination3Id = combination3.id(); + *config.add_predicate() = combination3; + + EXPECT_TRUE(initConfig(config)); + + // Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced. + set<int64_t> replacedMatchers; + replacedMatchers.insert(matcher6Id); + + // Change the condition of simple1 to true. + ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id); + LogEvent event(/*uid=*/0, /*pid=*/0); // Empty event is fine since there are no dimensions. + // Mark the stop matcher as matched, condition should be false. + vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched); + eventMatcherValues[1] = MatchingState::kMatched; + vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated); + vector<bool> conditionChangeCache(6, false); + oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers, + tmpConditionCache, conditionChangeCache); + EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse); + EXPECT_EQ(conditionChangeCache[0], true); + + // New combination matcher. Should have an initial condition of true since it is NOT(simple1). + Predicate combination4; + combination4.set_id(StringToId("COMBINATION4")); + combination4.mutable_combination()->set_operation(LogicalOperation::NOT); + combination4.mutable_combination()->add_predicate(simple1Id); + int64_t combination4Id = combination4.id(); + *config.add_predicate() = combination4; + + // Map the matchers in reverse order to force the indices to change. + std::unordered_map<int64_t, int> newAtomMatchingTrackerMap; + const int matcher6Index = 0; + newAtomMatchingTrackerMap[matcher6Id] = 0; + const int matcher5Index = 1; + newAtomMatchingTrackerMap[matcher5Id] = 1; + const int matcher4Index = 2; + newAtomMatchingTrackerMap[matcher4Id] = 2; + const int matcher3Index = 3; + newAtomMatchingTrackerMap[matcher3Id] = 3; + const int matcher2Index = 4; + newAtomMatchingTrackerMap[matcher2Id] = 4; + const int matcher1Index = 5; + newAtomMatchingTrackerMap[matcher1Id] = 5; + + StatsdConfig newConfig; + *newConfig.add_predicate() = simple3; + const int simple3Index = 0; + *newConfig.add_predicate() = combination2; + const int combination2Index = 1; + *newConfig.add_predicate() = combination4; + const int combination4Index = 2; + *newConfig.add_predicate() = simple2; + const int simple2Index = 3; + *newConfig.add_predicate() = combination1; + const int combination1Index = 4; + *newConfig.add_predicate() = simple1; + const int simple1Index = 5; + + unordered_map<int64_t, int> newConditionTrackerMap; + vector<sp<ConditionTracker>> newConditionTrackers; + unordered_map<int, vector<int>> trackerToConditionMap; + std::vector<ConditionState> conditionCache; + std::set<int64_t> replacedConditions; + EXPECT_TRUE(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers, + oldConditionTrackerMap, oldConditionTrackers, + newConditionTrackerMap, newConditionTrackers, + trackerToConditionMap, conditionCache, replacedConditions)); + + unordered_map<int64_t, int> expectedConditionTrackerMap = { + {simple1Id, simple1Index}, {simple2Id, simple2Index}, + {simple3Id, simple3Index}, {combination1Id, combination1Index}, + {combination2Id, combination2Index}, {combination4Id, combination4Index}, + }; + EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap)); + + ASSERT_EQ(newConditionTrackers.size(), 6); + // Make sure all conditions are initialized: + for (const sp<ConditionTracker>& tracker : newConditionTrackers) { + EXPECT_TRUE(tracker->mInitialized); + } + + // Make sure preserved conditions are the same. + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)], + newConditionTrackers[newConditionTrackerMap.at(simple1Id)]); + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)], + newConditionTrackers[newConditionTrackerMap.at(simple2Id)]); + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)], + newConditionTrackers[newConditionTrackerMap.at(combination1Id)]); + + // Make sure replaced conditions are different and included in replacedConditions. + EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)], + newConditionTrackers[newConditionTrackerMap.at(simple3Id)]); + EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)], + newConditionTrackers[newConditionTrackerMap.at(combination2Id)]); + EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id}))); + + // Verify the trackerToConditionMap + ASSERT_EQ(trackerToConditionMap.size(), 6); + const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index]; + EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index, + combination2Index, combination4Index)); + const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index]; + EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index, + combination2Index, combination4Index)); + const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index]; + EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index)); + const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index]; + EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index)); + const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index]; + EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index)); + const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index]; + EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index)); + + // Verify the conditionCache. Specifically, simple1 is false and combination4 is true. + ASSERT_EQ(conditionCache.size(), 6); + EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse); + EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue); + + // Verify tracker indices/ids are correct. + EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id); + EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index); + EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id); + EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index); + EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id); + EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index); + EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id); + EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index); + EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id); + EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index); + EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id); + EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index); + EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition()); + + // Verify preserved trackers have indices updated. + SimpleConditionTracker* simpleTracker1 = + static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get()); + EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index); + EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index); + EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1); + + SimpleConditionTracker* simpleTracker2 = + static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get()); + EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index); + EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index); + EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1); + + CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>( + newConditionTrackers[combination1Index].get()); + EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index)); + EXPECT_THAT(combinationTracker1->mUnSlicedChildren, + UnorderedElementsAre(simple1Index, simple2Index)); + EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty()); +} +} // namespace statsd +} // namespace os +} // namespace android + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp new file mode 100644 index 000000000000..0d0a8960043e --- /dev/null +++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp @@ -0,0 +1,802 @@ +// 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. + +#include "src/metrics/parsing_utils/metrics_manager_util.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <private/android_filesystem_config.h> +#include <stdio.h> + +#include <set> +#include <unordered_map> +#include <vector> + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "src/condition/ConditionTracker.h" +#include "src/matchers/AtomMatchingTracker.h" +#include "src/metrics/CountMetricProducer.h" +#include "src/metrics/GaugeMetricProducer.h" +#include "src/metrics/MetricProducer.h" +#include "src/metrics/ValueMetricProducer.h" +#include "src/state/StateManager.h" +#include "tests/metrics/metrics_test_helper.h" +#include "tests/statsd_test_util.h" + +using namespace testing; +using android::sp; +using android::os::statsd::Predicate; +using std::map; +using std::set; +using std::unordered_map; +using std::vector; + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +namespace { +const ConfigKey kConfigKey(0, 12345); +const long kAlertId = 3; + +const long timeBaseSec = 1000; + +StatsdConfig buildGoodConfig() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); + + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + combination->add_matcher(StringToId("SCREEN_IS_OFF")); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_IS_ON")); + metric->set_bucket(ONE_MINUTE); + metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + config.add_no_report_metric(3); + + auto alert = config.add_alert(); + alert->set_id(kAlertId); + alert->set_metric_id(3); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildCircleMatchers() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + // Circle dependency + combination->add_matcher(StringToId("SCREEN_ON_OR_OFF")); + + return config; +} + +StatsdConfig buildAlertWithUnknownMetric() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_IS_ON")); + metric->set_bucket(ONE_MINUTE); + metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + auto alert = config.add_alert(); + alert->set_id(3); + alert->set_metric_id(2); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildMissingMatchers() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + // undefined matcher + combination->add_matcher(StringToId("ABC")); + + return config; +} + +StatsdConfig buildMissingPredicate() { + StatsdConfig config; + config.set_id(12345); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_EVENT")); + metric->set_bucket(ONE_MINUTE); + metric->set_condition(StringToId("SOME_CONDITION")); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_EVENT")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2); + + return config; +} + +StatsdConfig buildDimensionMetricsWithMultiTags() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_VERY_LOW")); + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW")); + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(3); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_LOW")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("BATTERY_VERY_LOW")); + combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW")); + + // Count process state changes, slice by uid, while SCREEN_IS_OFF + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("BATTERY_LOW")); + metric->set_bucket(ONE_MINUTE); + // This case is interesting. We want to dimension across two atoms. + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + auto alert = config.add_alert(); + alert->set_id(kAlertId); + alert->set_metric_id(3); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildCirclePredicates() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); + + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); + + auto condition = config.add_predicate(); + condition->set_id(StringToId("SCREEN_IS_ON")); + SimplePredicate* simplePredicate = condition->mutable_simple_predicate(); + simplePredicate->set_start(StringToId("SCREEN_IS_ON")); + simplePredicate->set_stop(StringToId("SCREEN_IS_OFF")); + + condition = config.add_predicate(); + condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF")); + + Predicate_Combination* combination = condition->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_predicate(StringToId("SCREEN_IS_ON")); + combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF")); + + return config; +} + +StatsdConfig buildConfigWithDifferentPredicates() { + StatsdConfig config; + config.set_id(12345); + + auto pulledAtomMatcher = + CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE); + *config.add_atom_matcher() = pulledAtomMatcher; + auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnAtomMatcher; + auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffAtomMatcher; + auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher(); + *config.add_atom_matcher() = batteryNoneAtomMatcher; + auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher(); + *config.add_atom_matcher() = batteryUsbAtomMatcher; + + // Simple condition with InitialValue set to default (unknown). + auto screenOnUnknownPredicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = screenOnUnknownPredicate; + + // Simple condition with InitialValue set to false. + auto screenOnFalsePredicate = config.add_predicate(); + screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse")); + SimplePredicate* simpleScreenOnFalsePredicate = + screenOnFalsePredicate->mutable_simple_predicate(); + simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id()); + simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id()); + simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); + + // Simple condition with InitialValue set to false. + auto onBatteryFalsePredicate = config.add_predicate(); + onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse")); + SimplePredicate* simpleOnBatteryFalsePredicate = + onBatteryFalsePredicate->mutable_simple_predicate(); + simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id()); + simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id()); + simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); + + // Combination condition with both simple condition InitialValues set to false. + auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate(); + screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse")); + screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation( + LogicalOperation::AND); + addPredicateToPredicateCombination(*screenOnFalsePredicate, + screenOnFalseOnBatteryFalsePredicate); + addPredicateToPredicateCombination(*onBatteryFalsePredicate, + screenOnFalseOnBatteryFalsePredicate); + + // Combination condition with one simple condition InitialValue set to unknown and one set to + // false. + auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate(); + screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse")); + screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation( + LogicalOperation::AND); + addPredicateToPredicateCombination(screenOnUnknownPredicate, + screenOnUnknownOnBatteryFalsePredicate); + addPredicateToPredicateCombination(*onBatteryFalsePredicate, + screenOnUnknownOnBatteryFalsePredicate); + + // Simple condition metric with initial value false. + ValueMetric* metric1 = config.add_value_metric(); + metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse")); + metric1->set_what(pulledAtomMatcher.id()); + *metric1->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric1->set_bucket(FIVE_MINUTES); + metric1->set_condition(screenOnFalsePredicate->id()); + + // Simple condition metric with initial value unknown. + ValueMetric* metric2 = config.add_value_metric(); + metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown")); + metric2->set_what(pulledAtomMatcher.id()); + *metric2->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric2->set_bucket(FIVE_MINUTES); + metric2->set_condition(screenOnUnknownPredicate.id()); + + // Combination condition metric with initial values false and false. + ValueMetric* metric3 = config.add_value_metric(); + metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse")); + metric3->set_what(pulledAtomMatcher.id()); + *metric3->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric3->set_bucket(FIVE_MINUTES); + metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id()); + + // Combination condition metric with initial values unknown and false. + ValueMetric* metric4 = config.add_value_metric(); + metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse")); + metric4->set_what(pulledAtomMatcher.id()); + *metric4->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric4->set_bucket(FIVE_MINUTES); + metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id()); + + return config; +} +} // anonymous namespace + +TEST(MetricsManagerTest, TestInitialConditions) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildConfigWithDifferentPredicates(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_TRUE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); + ASSERT_EQ(4u, allMetricProducers.size()); + ASSERT_EQ(5u, allConditionTrackers.size()); + + ConditionKey queryKey; + vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated); + + allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); + allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); + EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[1]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[2]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[3]); + EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]); + + EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition); + EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition); + EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition); + EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition); +} + +TEST(MetricsManagerTest, TestGoodConfig) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildGoodConfig(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_TRUE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); + ASSERT_EQ(1u, allMetricProducers.size()); + EXPECT_THAT(metricProducerMap, UnorderedElementsAre(Pair(config.count_metric(0).id(), 0))); + ASSERT_EQ(1u, allAnomalyTrackers.size()); + ASSERT_EQ(1u, noReportMetricIds.size()); + ASSERT_EQ(1u, alertTrackerMap.size()); + EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end()); + EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0); +} + +TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildDimensionMetricsWithMultiTags(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildCircleMatchers(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestMissingMatchers) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildMissingMatchers(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestMissingPredicate) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildMissingPredicate(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCirclePredicateDependency) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildCirclePredicates(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, testAlertWithUnknownMetric) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildAlertWithUnknownMetric(); + set<int> allTagIds; + vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; + unordered_map<int64_t, int> atomMatchingTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; + vector<sp<MetricProducer>> allMetricProducers; + unordered_map<int64_t, int> metricProducerMap; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + map<int64_t, uint64_t> stateProtoHashes; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap, + allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, + trackerToConditionMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + stateProtoHashes, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerInvalidMatcher) { + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + // Matcher has no contents_case (simple/combination), so it is invalid. + matcher.set_id(21); + EXPECT_EQ(createAtomMatchingTracker(matcher, 0, uidMap), nullptr); +} + +TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerSimple) { + int index = 1; + int64_t id = 123; + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + matcher.set_id(id); + SimpleAtomMatcher* simpleAtomMatcher = matcher.mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(util::SCREEN_STATE_CHANGED); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + + sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, index, uidMap); + EXPECT_NE(tracker, nullptr); + + EXPECT_TRUE(tracker->mInitialized); + EXPECT_EQ(tracker->getId(), id); + EXPECT_EQ(tracker->mIndex, index); + const set<int>& atomIds = tracker->getAtomIds(); + ASSERT_EQ(atomIds.size(), 1); + EXPECT_EQ(atomIds.count(util::SCREEN_STATE_CHANGED), 1); +} + +TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination) { + int index = 1; + int64_t id = 123; + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + matcher.set_id(id); + AtomMatcher_Combination* combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(123); + combination->add_matcher(223); + + sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, index, uidMap); + EXPECT_NE(tracker, nullptr); + + // Combination matchers need to be initialized first. + EXPECT_FALSE(tracker->mInitialized); + EXPECT_EQ(tracker->getId(), id); + EXPECT_EQ(tracker->mIndex, index); + const set<int>& atomIds = tracker->getAtomIds(); + ASSERT_EQ(atomIds.size(), 0); +} + +TEST(MetricsManagerTest, TestCreateConditionTrackerInvalid) { + const ConfigKey key(123, 456); + // Predicate has no contents_case (simple/combination), so it is invalid. + Predicate predicate; + predicate.set_id(21); + unordered_map<int64_t, int> atomTrackerMap; + EXPECT_EQ(createConditionTracker(key, predicate, 0, atomTrackerMap), nullptr); +} + +TEST(MetricsManagerTest, TestCreateConditionTrackerSimple) { + int index = 1; + int64_t id = 987; + const ConfigKey key(123, 456); + + int startMatcherIndex = 2, stopMatcherIndex = 0, stopAllMatcherIndex = 1; + int64_t startMatcherId = 246, stopMatcherId = 153, stopAllMatcherId = 975; + + Predicate predicate; + predicate.set_id(id); + SimplePredicate* simplePredicate = predicate.mutable_simple_predicate(); + simplePredicate->set_start(startMatcherId); + simplePredicate->set_stop(stopMatcherId); + simplePredicate->set_stop_all(stopAllMatcherId); + + unordered_map<int64_t, int> atomTrackerMap; + atomTrackerMap[startMatcherId] = startMatcherIndex; + atomTrackerMap[stopMatcherId] = stopMatcherIndex; + atomTrackerMap[stopAllMatcherId] = stopAllMatcherIndex; + + sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap); + EXPECT_EQ(tracker->getConditionId(), id); + EXPECT_EQ(tracker->isSliced(), false); + EXPECT_TRUE(tracker->IsSimpleCondition()); + const set<int>& interestedMatchers = tracker->getAtomMatchingTrackerIndex(); + ASSERT_EQ(interestedMatchers.size(), 3); + ASSERT_EQ(interestedMatchers.count(startMatcherIndex), 1); + ASSERT_EQ(interestedMatchers.count(stopMatcherIndex), 1); + ASSERT_EQ(interestedMatchers.count(stopAllMatcherIndex), 1); +} + +TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) { + int index = 1; + int64_t id = 987; + const ConfigKey key(123, 456); + + Predicate predicate; + predicate.set_id(id); + Predicate_Combination* combinationPredicate = predicate.mutable_combination(); + combinationPredicate->set_operation(LogicalOperation::AND); + combinationPredicate->add_predicate(888); + combinationPredicate->add_predicate(777); + + // Combination conditions must be initialized to set most state. + unordered_map<int64_t, int> atomTrackerMap; + sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap); + EXPECT_EQ(tracker->getConditionId(), id); + EXPECT_FALSE(tracker->IsSimpleCondition()); +} + +} // namespace statsd +} // namespace os +} // namespace android + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp index e384b6ac7c84..4fa4135e983f 100644 --- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp +++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp @@ -190,9 +190,9 @@ TEST(ShellSubscriberTest, testPulledSubscription) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); const vector<int32_t> uids = {AID_SYSTEM}; - EXPECT_CALL(*pullerManager, Pull(10016, uids, _, _, _)) + EXPECT_CALL(*pullerManager, Pull(10016, uids, _, _)) .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&, const int64_t, - vector<std::shared_ptr<LogEvent>>* data, bool) { + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1)); data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid2, /*timeMillis=*/kCpuTime2)); diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index cee83725d075..1761d5d9e1fa 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -15,6 +15,8 @@ #include "statsd_test_util.h" #include <aidl/android/util/StatsEventParcel.h> + +#include "matchers/SimpleAtomMatchingTracker.h" #include "stats_event.h" using aidl::android::util::StatsEventParcel; @@ -996,6 +998,20 @@ int64_t StringToId(const string& str) { return static_cast<int64_t>(std::hash<std::string>()(str)); } +sp<EventMatcherWizard> createEventMatcherWizard( + int tagId, int matcherIndex, const vector<FieldValueMatcher>& fieldValueMatchers) { + sp<UidMap> uidMap = new UidMap(); + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + for (const FieldValueMatcher& fvm : fieldValueMatchers) { + *atomMatcher.add_field_value_matcher() = fvm; + } + uint64_t matcherHash = 0x12345678; + int64_t matcherId = 678; + return new EventMatcherWizard({new SimpleAtomMatchingTracker( + matcherId, matcherIndex, matcherHash, atomMatcher, uidMap)}); +} + void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId, const int uid, const string& tag) { EXPECT_EQ(value.field(), atomId); diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 3dcf4ecce054..1220019e2353 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -25,6 +25,7 @@ #include "src/StatsLogProcessor.h" #include "src/hash.h" #include "src/logd/LogEvent.h" +#include "src/matchers/EventMatcherWizard.h" #include "src/packages/UidMap.h" #include "src/stats_log_util.h" #include "stats_event.h" @@ -335,6 +336,9 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events); int64_t StringToId(const string& str); +sp<EventMatcherWizard> createEventMatcherWizard( + int tagId, int matcherIndex, const std::vector<FieldValueMatcher>& fieldValueMatchers = {}); + void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId, const int uid, const string& tag); void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid); diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp new file mode 100644 index 000000000000..0d7fed2a15c7 --- /dev/null +++ b/cmds/uinput/Android.bp @@ -0,0 +1,18 @@ +// Copyright 2020 The Android Open Source Project +// + +java_binary { + name: "uinput", + wrapper: "uinput", + srcs: ["**/*.java", + ":uinputcommand_aidl" + ], + required: ["libuinputcommand_jni"], +} + +filegroup { + name: "uinputcommand_aidl", + srcs: [ + "src/com/android/commands/uinput/InputAbsInfo.aidl", + ], +}
\ No newline at end of file diff --git a/cmds/uinput/MODULE_LICENSE_APACHE2 b/cmds/uinput/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/cmds/uinput/MODULE_LICENSE_APACHE2 diff --git a/cmds/uinput/NOTICE b/cmds/uinput/NOTICE new file mode 100644 index 000000000000..c5b1efa7aac7 --- /dev/null +++ b/cmds/uinput/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md new file mode 100644 index 000000000000..47e1dad9ccd6 --- /dev/null +++ b/cmds/uinput/README.md @@ -0,0 +1,166 @@ +# Usage +## Two options to use the uinput command: +### 1. Interactive through stdin: +type `uinput -` into the terminal, then type/paste commands to send to the binary. +Use Ctrl+D to signal end of stream to the binary (EOF). + +This mode can be also used from an app to send uinput events. +For an example, see the cts test case at: [InputTestCase.java][2] + +When using another program to control uinput in interactive mode, registering a +new input device (for example, a bluetooth joystick) should be the first step. +After the device is added, you need to wait for the _onInputDeviceAdded_ +(see [InputDeviceListener][1]) notification before issuing commands +to the device. +Failure to do so will cause missed events and inconsistent behavior. + +### 2. Using a file as an input: +type `uinput <filename>`, and the file will be used an an input to the binary. +You must add a sufficient delay after a "register" command to ensure device +is ready. The interactive mode is the recommended method of communicating +with the uinput binary. + +All of the input commands should be in pseudo-JSON format as documented below. +See examples [here][3]. + +The file can have multiple commands one after the other (which is not strictly +legal JSON format, as this would imply multiple root elements). + +## Command description + +1. `register` +Register a new uinput device + +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| id | integer | Device id | +| command | string | Must be set to "register" | +| name | string | Device name | +| vid | 16-bit integer| Vendor id | +| pid | 16-bit integer| Product id | +| bus | string | Bus that device should use | +| configuration | int array | uinput device configuration| +| ff_effects_max| integer | ff_effects_max value | +| abs_info | array | ABS axes information | + +Device ID is used for matching the subsequent commands to a specific device +to avoid ambiguity when multiple devices are registered. + +Device bus is used to determine how the uinput device is connected to the host. +The options are "usb" and "bluetooth". + +Device configuration is used to configure uinput device. "type" field provides the UI_SET_* +control code, and data is a vector of control values to be sent to uinput device, depends on +the control code. + +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| type | integer | UI_SET_ control type | +| data | int array | control values | + +Device ff_effects_max must be provided if FFBIT is set. + +Device abs_info fields are provided to set the device axes information. It is an array of below +objects: +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| code | integer | Axis code | +| info | object | ABS information object | + +ABS information object is defined as below: +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| value | integer | Latest reported value | +| minimum | integer | Minimum value for the axis | +| maximum | integer | Maximum value for the axis | +| fuzz | integer | fuzz value for noise filter| +| flat | integer | values to be discarded | +| resolution | integer | resolution of axis | + +See [struct input_absinfo][4]) definitions. + +Example: +```json + +{ + "id": 1, + "command": "register", + "name": "Keyboard (Test)", + "vid": 0x18d2, + "pid": 0x2c42, + "bus": "usb", + "configuration":[ + {"type":100, "data":[1, 21]}, // UI_SET_EVBIT : EV_KEY and EV_FF + {"type":101, "data":[11, 2, 3, 4]}, // UI_SET_KEYBIT : KEY_0 KEY_1 KEY_2 KEY_3 + {"type":107, "data":[80]} // UI_SET_FFBIT : FF_RUMBLE + ], + "ff_effects_max" : 1, + "abs_info": [ + {"code":1, "info": {"value":20, "minimum":-255, + "maximum":255, "fuzz":0, "flat":0, "resolution":1} + }, + {"code":8, "info": {"value":-50, "minimum":-255, + "maximum":255, "fuzz":0, "flat":0, "resolution":1} + } + ] +} + +``` +2. `delay` +Add a delay to command processing + +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| id | integer | Device id | +| command | string | Must be set to "delay" | +| duration | integer | Delay in milliseconds | + +Example: +```json +{ + "id": 1, + "command": "delay", + "duration": 10 +} +``` + +3. `inject` +Send an array of uinput event packets [type, code, value] to the uinput device + +| Field | Type | Description | +|:-------------:|:-------------:|:-------------------------- | +| id | integer | Device id | +| command | string | Must be set to "inject" | +| events | integer array | events to inject | + +The "events" parameter is an array of integers, encapsulates evdev input_event type, code and value, +see the example below. + +Example: +```json +{ + "id": 1, + "command": "inject", + "events": [0x01, 0xb, 0x1, // EV_KEY, KEY_0, DOWN + 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0 + 0x01, 0x0b, 0x00, // EV_KEY, KEY_0, UP + 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0 + 0x01, 0x2, 0x1, // EV_KEY, KEY_1, DOWN + 0x00, 0x00, 0x01, // EV_SYN, SYN_REPORT, 0 + 0x01, 0x02, 0x00, // EV_KEY, KEY_1, UP + 0x00, 0x00, 0x01 // EV_SYN, SYN_REPORT, 0 + ] +} +``` + +### Notes +1. As soon as EOF is reached (either in interactive mode, or in file mode), +the device that was created will be unregistered. There is no +explicit command for unregistering a device. +2. The `getevent` utility can used to print out the key events +for debugging purposes. + +[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html +[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java +[3]: ../../../../cts/tests/tests/hardware/res/raw/ +[4]: ../../../../bionic/libc/kernel/uapi/linux/input.h diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp new file mode 100644 index 000000000000..199bbbd35274 --- /dev/null +++ b/cmds/uinput/jni/Android.bp @@ -0,0 +1,23 @@ +cc_library_shared { + name: "libuinputcommand_jni", + + srcs: [ + "com_android_commands_uinput_Device.cpp", + ":uinputcommand_aidl", + ], + + shared_libs: [ + "libandroid", + "libandroid_runtime_lazy", + "libbase", + "libbinder", + "liblog", + "libnativehelper", + ], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp new file mode 100644 index 000000000000..06fa2aac2c7e --- /dev/null +++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp @@ -0,0 +1,351 @@ +/* + * 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. + */ + +#define LOG_TAG "UinputCommandDevice" + +#include <linux/uinput.h> + +#include <fcntl.h> +#include <inttypes.h> +#include <time.h> +#include <unistd.h> +#include <algorithm> +#include <array> +#include <cstdio> +#include <cstring> +#include <iterator> +#include <memory> +#include <vector> + +#include <android/looper.h> +#include <android_os_Parcel.h> +#include <jni.h> +#include <log/log.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedLocalRef.h> +#include <nativehelper/ScopedPrimitiveArray.h> +#include <nativehelper/ScopedUtfChars.h> + +#include <android-base/stringprintf.h> + +#include "com_android_commands_uinput_Device.h" + +namespace android { +namespace uinput { + +using src::com::android::commands::uinput::InputAbsInfo; + +static constexpr const char* UINPUT_PATH = "/dev/uinput"; + +static struct { + jmethodID onDeviceConfigure; + jmethodID onDeviceVibrating; + jmethodID onDeviceError; +} gDeviceCallbackClassInfo; + +static void checkAndClearException(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + ALOGE("An exception was thrown by callback '%s'.", methodName); + env->ExceptionClear(); + } +} + +DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) + : mCallbackObject(env->NewGlobalRef(callback)) { + env->GetJavaVM(&mJavaVM); +} + +DeviceCallback::~DeviceCallback() { + JNIEnv* env = getJNIEnv(); + env->DeleteGlobalRef(mCallbackObject); +} + +void DeviceCallback::onDeviceError() { + JNIEnv* env = getJNIEnv(); + env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError); + checkAndClearException(env, "onDeviceError"); +} + +void DeviceCallback::onDeviceConfigure(int handle) { + JNIEnv* env = getJNIEnv(); + env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceConfigure, handle); + checkAndClearException(env, "onDeviceConfigure"); +} + +void DeviceCallback::onDeviceVibrating(int value) { + JNIEnv* env = getJNIEnv(); + env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceVibrating, value); + checkAndClearException(env, "onDeviceVibrating"); +} + +JNIEnv* DeviceCallback::getJNIEnv() { + JNIEnv* env; + mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); + return env; +} + +std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid, + int32_t pid, uint16_t bus, uint32_t ffEffectsMax, + std::unique_ptr<DeviceCallback> callback) { + android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC)); + if (!fd.ok()) { + ALOGE("Failed to open uinput: %s", strerror(errno)); + return nullptr; + } + + int32_t version; + ::ioctl(fd, UI_GET_VERSION, &version); + if (version < 5) { + ALOGE("Kernel version %d older than 5 is not supported", version); + return nullptr; + } + + struct uinput_setup setupDescriptor; + memset(&setupDescriptor, 0, sizeof(setupDescriptor)); + strlcpy(setupDescriptor.name, name, UINPUT_MAX_NAME_SIZE); + setupDescriptor.id.version = 1; + setupDescriptor.id.bustype = bus; + setupDescriptor.id.vendor = vid; + setupDescriptor.id.product = pid; + setupDescriptor.ff_effects_max = ffEffectsMax; + + // Request device configuration. + callback->onDeviceConfigure(fd.get()); + + // register the input device + if (::ioctl(fd, UI_DEV_SETUP, &setupDescriptor)) { + ALOGE("UI_DEV_SETUP ioctl failed on fd %d: %s.", fd.get(), strerror(errno)); + return nullptr; + } + + if (::ioctl(fd, UI_DEV_CREATE) != 0) { + ALOGE("Unable to create uinput device: %s.", strerror(errno)); + return nullptr; + } + + // using 'new' to access non-public constructor + return std::unique_ptr<UinputDevice>(new UinputDevice(id, std::move(fd), std::move(callback))); +} + +UinputDevice::UinputDevice(int32_t id, android::base::unique_fd fd, + std::unique_ptr<DeviceCallback> callback) + : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) { + ALooper* aLooper = ALooper_forThread(); + if (aLooper == nullptr) { + ALOGE("Could not get ALooper, ALooper_forThread returned NULL"); + aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + } + ALooper_addFd( + aLooper, mFd, 0, ALOOPER_EVENT_INPUT, + [](int, int events, void* data) { + UinputDevice* d = reinterpret_cast<UinputDevice*>(data); + return d->handleEvents(events); + }, + reinterpret_cast<void*>(this)); + ALOGI("uinput device %d created: version = %d, fd = %d", mId, UINPUT_VERSION, mFd.get()); +} + +UinputDevice::~UinputDevice() { + ::ioctl(mFd, UI_DEV_DESTROY); +} + +void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) { + struct input_event event = {}; + event.type = type; + event.code = code; + event.value = value; + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + TIMESPEC_TO_TIMEVAL(&event.time, &ts); + + if (::write(mFd, &event, sizeof(input_event)) < 0) { + ALOGE("Could not write event %" PRIu16 " %" PRIu16 " with value %" PRId32 " : %s", type, + code, value, strerror(errno)); + } +} + +int UinputDevice::handleEvents(int events) { + if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { + ALOGE("uinput node was closed or an error occurred. events=0x%x", events); + mDeviceCallback->onDeviceError(); + return 0; + } + struct input_event ev; + ssize_t ret = ::read(mFd, &ev, sizeof(ev)); + if (ret < 0) { + ALOGE("Failed to read from uinput node: %s", strerror(errno)); + mDeviceCallback->onDeviceError(); + return 0; + } + + switch (ev.type) { + case EV_UINPUT: { + if (ev.code == UI_FF_UPLOAD) { + struct uinput_ff_upload ff_upload; + ff_upload.request_id = ev.value; + ::ioctl(mFd, UI_BEGIN_FF_UPLOAD, &ff_upload); + ff_upload.retval = 0; + ::ioctl(mFd, UI_END_FF_UPLOAD, &ff_upload); + } else if (ev.code == UI_FF_ERASE) { + struct uinput_ff_erase ff_erase; + ff_erase.request_id = ev.value; + ::ioctl(mFd, UI_BEGIN_FF_ERASE, &ff_erase); + ff_erase.retval = 0; + ::ioctl(mFd, UI_END_FF_ERASE, &ff_erase); + } + break; + } + case EV_FF: { + ALOGI("EV_FF effect = %d value = %d", ev.code, ev.value); + mDeviceCallback->onDeviceVibrating(ev.value); + break; + } + default: { + ALOGI("Unhandled event type: %" PRIu32, ev.type); + break; + } + } + + return 1; +} + +} // namespace uinput + +std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) { + std::vector<int32_t> data; + if (javaArray == nullptr) { + return data; + } + + ScopedIntArrayRO scopedArray(env, javaArray); + size_t size = scopedArray.size(); + data.reserve(size); + for (size_t i = 0; i < size; i++) { + data.push_back(static_cast<int32_t>(scopedArray[i])); + } + return data; +} + +static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, + jint pid, jint bus, jint ffEffectsMax, jobject callback) { + ScopedUtfChars name(env, rawName); + if (name.c_str() == nullptr) { + return 0; + } + + std::unique_ptr<uinput::DeviceCallback> cb = + std::make_unique<uinput::DeviceCallback>(env, callback); + + std::unique_ptr<uinput::UinputDevice> d = + uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax, + std::move(cb)); + return reinterpret_cast<jlong>(d.release()); +} + +static void closeUinputDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { + uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr); + if (d != nullptr) { + delete d; + } +} + +static void injectEvent(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint type, jint code, + jint value) { + uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr); + if (d != nullptr) { + d->injectEvent(static_cast<uint16_t>(type), static_cast<uint16_t>(code), + static_cast<int32_t>(value)); + } else { + ALOGE("Could not inject event, Device* is null!"); + } +} + +static void configure(JNIEnv* env, jclass /* clazz */, jint handle, jint code, + jintArray rawConfigs) { + std::vector<int32_t> configs = toVector(env, rawConfigs); + // Configure uinput device, with user specified code and value. + for (auto& config : configs) { + ::ioctl(static_cast<int>(handle), _IOW(UINPUT_IOCTL_BASE, code, int), config); + } +} + +static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCode, + jobject infoObj) { + Parcel* parcel = parcelForJavaObject(env, infoObj); + uinput::InputAbsInfo info; + + info.readFromParcel(parcel); + + struct uinput_abs_setup absSetup; + absSetup.code = axisCode; + absSetup.absinfo.maximum = info.maximum; + absSetup.absinfo.minimum = info.minimum; + absSetup.absinfo.value = info.value; + absSetup.absinfo.fuzz = info.fuzz; + absSetup.absinfo.flat = info.flat; + absSetup.absinfo.resolution = info.resolution; + + ::ioctl(static_cast<int>(handle), UI_ABS_SETUP, &absSetup); +} + +static JNINativeMethod sMethods[] = { + {"nativeOpenUinputDevice", + "(Ljava/lang/String;IIIII" + "Lcom/android/commands/uinput/Device$DeviceCallback;)J", + reinterpret_cast<void*>(openUinputDevice)}, + {"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)}, + {"nativeConfigure", "(II[I)V", reinterpret_cast<void*>(configure)}, + {"nativeSetAbsInfo", "(IILandroid/os/Parcel;)V", reinterpret_cast<void*>(setAbsInfo)}, + {"nativeCloseUinputDevice", "(J)V", reinterpret_cast<void*>(closeUinputDevice)}, +}; + +int register_com_android_commands_uinput_Device(JNIEnv* env) { + jclass clazz = env->FindClass("com/android/commands/uinput/Device$DeviceCallback"); + if (clazz == nullptr) { + ALOGE("Unable to find class 'DeviceCallback'"); + return JNI_ERR; + } + + uinput::gDeviceCallbackClassInfo.onDeviceConfigure = + env->GetMethodID(clazz, "onDeviceConfigure", "(I)V"); + uinput::gDeviceCallbackClassInfo.onDeviceVibrating = + env->GetMethodID(clazz, "onDeviceVibrating", "(I)V"); + uinput::gDeviceCallbackClassInfo.onDeviceError = + env->GetMethodID(clazz, "onDeviceError", "()V"); + if (uinput::gDeviceCallbackClassInfo.onDeviceConfigure == nullptr || + uinput::gDeviceCallbackClassInfo.onDeviceError == nullptr || + uinput::gDeviceCallbackClassInfo.onDeviceVibrating == nullptr) { + ALOGE("Unable to obtain onDeviceConfigure or onDeviceError or onDeviceVibrating methods"); + return JNI_ERR; + } + return jniRegisterNativeMethods(env, "com/android/commands/uinput/Device", sMethods, + NELEM(sMethods)); +} + +} // namespace android + +jint JNI_OnLoad(JavaVM* jvm, void*) { + JNIEnv* env = nullptr; + if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) { + return JNI_ERR; + } + + if (android::register_com_android_commands_uinput_Device(env) < 0) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h new file mode 100644 index 000000000000..5a9a06cfb32e --- /dev/null +++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#include <memory> +#include <vector> + +#include <jni.h> +#include <linux/input.h> + +#include <android-base/unique_fd.h> +#include "src/com/android/commands/uinput/InputAbsInfo.h" + +namespace android { +namespace uinput { + +class DeviceCallback { +public: + DeviceCallback(JNIEnv* env, jobject callback); + ~DeviceCallback(); + + void onDeviceOpen(); + void onDeviceGetReport(uint32_t requestId, uint8_t reportId); + void onDeviceOutput(const std::vector<uint8_t>& data); + void onDeviceConfigure(int handle); + void onDeviceVibrating(int value); + void onDeviceError(); + +private: + JNIEnv* getJNIEnv(); + jobject mCallbackObject; + JavaVM* mJavaVM; +}; + +class UinputDevice { +public: + static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid, + int32_t pid, uint16_t bus, uint32_t ff_effects_max, + std::unique_ptr<DeviceCallback> callback); + + virtual ~UinputDevice(); + + void injectEvent(uint16_t type, uint16_t code, int32_t value); + int handleEvents(int events); + +private: + UinputDevice(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback); + + int32_t mId; + android::base::unique_fd mFd; + std::unique_ptr<DeviceCallback> mDeviceCallback; +}; + +} // namespace uinput +} // namespace android diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java new file mode 100644 index 000000000000..62bee7b964bd --- /dev/null +++ b/cmds/uinput/src/com/android/commands/uinput/Device.java @@ -0,0 +1,232 @@ +/* + * 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. + */ + +package com.android.commands.uinput; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.os.SystemClock; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.os.SomeArgs; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.OutputStream; + +import src.com.android.commands.uinput.InputAbsInfo; + +/** + * Device class defines uinput device interfaces of device operations, for device open, close, + * configuration, events injection. + */ +public class Device { + private static final String TAG = "UinputDevice"; + + private static final int MSG_OPEN_UINPUT_DEVICE = 1; + private static final int MSG_CLOSE_UINPUT_DEVICE = 2; + private static final int MSG_INJECT_EVENT = 3; + + private final int mId; + private final HandlerThread mThread; + private final DeviceHandler mHandler; + // mConfiguration is sparse array of ioctl code and array of values. + private final SparseArray<int[]> mConfiguration; + private final SparseArray<InputAbsInfo> mAbsInfo; + private final OutputStream mOutputStream; + private final Object mCond = new Object(); + private long mTimeToSend; + + static { + System.loadLibrary("uinputcommand_jni"); + } + + private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid, + int bus, int ffEffectsMax, DeviceCallback callback); + private static native void nativeCloseUinputDevice(long ptr); + private static native void nativeInjectEvent(long ptr, int type, int code, int value); + private static native void nativeConfigure(int handle, int code, int[] configs); + private static native void nativeSetAbsInfo(int handle, int axisCode, Parcel axisParcel); + + public Device(int id, String name, int vid, int pid, int bus, + SparseArray<int[]> configuration, int ffEffectsMax, + SparseArray<InputAbsInfo> absInfo) { + mId = id; + mThread = new HandlerThread("UinputDeviceHandler"); + mThread.start(); + mHandler = new DeviceHandler(mThread.getLooper()); + mConfiguration = configuration; + mAbsInfo = absInfo; + mOutputStream = System.out; + SomeArgs args = SomeArgs.obtain(); + args.argi1 = id; + args.argi2 = vid; + args.argi3 = pid; + args.argi4 = bus; + args.argi5 = ffEffectsMax; + if (name != null) { + args.arg1 = name; + } else { + args.arg1 = id + ":" + vid + ":" + pid; + } + + mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget(); + mTimeToSend = SystemClock.uptimeMillis(); + } + + /** + * Inject uinput events to device + * + * @param events Array of raw uinput events. + */ + public void injectEvent(int[] events) { + // if two messages are sent at identical time, they will be processed in order received + Message msg = mHandler.obtainMessage(MSG_INJECT_EVENT, events); + mHandler.sendMessageAtTime(msg, mTimeToSend); + } + + /** + * Impose a delay to the device for execution. + * + * @param delay Time to delay in unit of milliseconds. + */ + public void addDelay(int delay) { + mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay; + } + + /** + * Close an uinput device. + * + */ + public void close() { + Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE); + mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1); + try { + synchronized (mCond) { + mCond.wait(); + } + } catch (InterruptedException ignore) { + } + } + + private class DeviceHandler extends Handler { + private long mPtr; + private int mBarrierToken; + + DeviceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_OPEN_UINPUT_DEVICE: + SomeArgs args = (SomeArgs) msg.obj; + mPtr = nativeOpenUinputDevice((String) args.arg1, args.argi1, args.argi2, + args.argi3, args.argi4, args.argi5, + new DeviceCallback()); + break; + case MSG_INJECT_EVENT: + if (mPtr != 0) { + int[] events = (int[]) msg.obj; + for (int pos = 0; pos + 2 < events.length; pos += 3) { + nativeInjectEvent(mPtr, events[pos], events[pos + 1], events[pos + 2]); + } + } + break; + case MSG_CLOSE_UINPUT_DEVICE: + if (mPtr != 0) { + nativeCloseUinputDevice(mPtr); + getLooper().quitSafely(); + mPtr = 0; + } else { + Log.e(TAG, "Tried to close already closed device."); + } + Log.i(TAG, "Device closed."); + synchronized (mCond) { + mCond.notify(); + } + break; + default: + throw new IllegalArgumentException("Unknown device message"); + } + } + + public void pauseEvents() { + mBarrierToken = getLooper().myQueue().postSyncBarrier(); + } + + public void resumeEvents() { + getLooper().myQueue().removeSyncBarrier(mBarrierToken); + mBarrierToken = 0; + } + } + + private class DeviceCallback { + public void onDeviceOpen() { + mHandler.resumeEvents(); + } + + public void onDeviceConfigure(int handle) { + for (int i = 0; i < mConfiguration.size(); i++) { + int key = mConfiguration.keyAt(i); + int[] data = mConfiguration.get(key); + nativeConfigure(handle, key, data); + } + + if (mAbsInfo != null) { + for (int i = 0; i < mAbsInfo.size(); i++) { + int key = mAbsInfo.keyAt(i); + InputAbsInfo info = mAbsInfo.get(key); + Parcel parcel = Parcel.obtain(); + info.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + nativeSetAbsInfo(handle, key, parcel); + } + } + } + + public void onDeviceVibrating(int value) { + JSONObject json = new JSONObject(); + try { + json.put("reason", "vibrating"); + json.put("id", mId); + json.put("status", value); + } catch (JSONException e) { + throw new RuntimeException("Could not create JSON object ", e); + } + try { + mOutputStream.write(json.toString().getBytes()); + mOutputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void onDeviceError() { + Log.e(TAG, "Device error occurred, closing /dev/uinput"); + Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE); + msg.setAsynchronous(true); + msg.sendToTarget(); + } + } +} diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java new file mode 100644 index 000000000000..c4ba05054eda --- /dev/null +++ b/cmds/uinput/src/com/android/commands/uinput/Event.java @@ -0,0 +1,454 @@ +/* + * 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. + */ + +package com.android.commands.uinput; + +import android.util.JsonReader; +import android.util.JsonToken; +import android.util.Log; +import android.util.SparseArray; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; + +import src.com.android.commands.uinput.InputAbsInfo; + +/** + * An event is a JSON file defined action event to instruct uinput to perform a command like + * device registration or uinput events injection. + */ +public class Event { + private static final String TAG = "UinputEvent"; + + public static final String COMMAND_REGISTER = "register"; + public static final String COMMAND_DELAY = "delay"; + public static final String COMMAND_INJECT = "inject"; + private static final int ABS_CNT = 64; + + // These constants come from "include/uapi/linux/input.h" in the kernel + enum Bus { + USB(0x03), BLUETOOTH(0x05); + private final int mValue; + + Bus(int value) { + mValue = value; + } + + int getValue() { + return mValue; + } + } + + private int mId; + private String mCommand; + private String mName; + private int mVid; + private int mPid; + private Bus mBus; + private int[] mInjections; + private SparseArray<int[]> mConfiguration; + private int mDuration; + private int mFfEffectsMax = 0; + private SparseArray<InputAbsInfo> mAbsInfo; + + public int getId() { + return mId; + } + + public String getCommand() { + return mCommand; + } + + public String getName() { + return mName; + } + + public int getVendorId() { + return mVid; + } + + public int getProductId() { + return mPid; + } + + public int getBus() { + return mBus.getValue(); + } + + public int[] getInjections() { + return mInjections; + } + + public SparseArray<int[]> getConfiguration() { + return mConfiguration; + } + + public int getDuration() { + return mDuration; + } + + public int getFfEffectsMax() { + return mFfEffectsMax; + } + + public SparseArray<InputAbsInfo> getAbsInfo() { + return mAbsInfo; + } + + /** + * Convert an event to String. + */ + public String toString() { + return "Event{id=" + mId + + ", command=" + mCommand + + ", name=" + mName + + ", vid=" + mVid + + ", pid=" + mPid + + ", bus=" + mBus + + ", events=" + Arrays.toString(mInjections) + + ", configuration=" + mConfiguration + + ", duration=" + mDuration + + ", ff_effects_max=" + mFfEffectsMax + + "}"; + } + + private static class Builder { + private Event mEvent; + + Builder() { + mEvent = new Event(); + } + + public void setId(int id) { + mEvent.mId = id; + } + + private void setCommand(String command) { + mEvent.mCommand = command; + } + + public void setName(String name) { + mEvent.mName = name; + } + + public void setInjections(int[] events) { + mEvent.mInjections = events; + } + + public void setConfiguration(SparseArray<int[]> configuration) { + mEvent.mConfiguration = configuration; + } + + public void setVid(int vid) { + mEvent.mVid = vid; + } + + public void setPid(int pid) { + mEvent.mPid = pid; + } + + public void setBus(Bus bus) { + mEvent.mBus = bus; + } + + public void setDuration(int duration) { + mEvent.mDuration = duration; + } + + public void setFfEffectsMax(int ffEffectsMax) { + mEvent.mFfEffectsMax = ffEffectsMax; + } + + public void setAbsInfo(SparseArray<InputAbsInfo> absInfo) { + mEvent.mAbsInfo = absInfo; + } + + public Event build() { + if (mEvent.mId == -1) { + throw new IllegalStateException("No event id"); + } else if (mEvent.mCommand == null) { + throw new IllegalStateException("Event does not contain a command"); + } + if (COMMAND_REGISTER.equals(mEvent.mCommand)) { + if (mEvent.mConfiguration == null) { + throw new IllegalStateException( + "Device registration is missing configuration"); + } + } else if (COMMAND_DELAY.equals(mEvent.mCommand)) { + if (mEvent.mDuration <= 0) { + throw new IllegalStateException("Delay has missing or invalid duration"); + } + } else if (COMMAND_INJECT.equals(mEvent.mCommand)) { + if (mEvent.mInjections == null) { + throw new IllegalStateException("Inject command is missing injection data"); + } + } else { + throw new IllegalStateException("Unknown command " + mEvent.mCommand); + } + return mEvent; + } + } + + /** + * A class that parses the JSON event format from an input stream to build device events. + */ + public static class Reader { + private JsonReader mReader; + + public Reader(InputStreamReader in) { + mReader = new JsonReader(in); + mReader.setLenient(true); + } + + /** + * Get next event entry from JSON file reader. + */ + public Event getNextEvent() throws IOException { + Event e = null; + while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) { + Event.Builder eb = new Event.Builder(); + try { + mReader.beginObject(); + while (mReader.hasNext()) { + String name = mReader.nextName(); + switch (name) { + case "id": + eb.setId(readInt()); + break; + case "command": + eb.setCommand(mReader.nextString()); + break; + case "name": + eb.setName(mReader.nextString()); + break; + case "vid": + eb.setVid(readInt()); + break; + case "pid": + eb.setPid(readInt()); + break; + case "bus": + eb.setBus(readBus()); + break; + case "events": + int[] injections = readIntList().stream() + .mapToInt(Integer::intValue).toArray(); + eb.setInjections(injections); + break; + case "configuration": + eb.setConfiguration(readConfiguration()); + break; + case "ff_effects_max": + eb.setFfEffectsMax(readInt()); + break; + case "abs_info": + eb.setAbsInfo(readAbsInfoArray()); + break; + case "duration": + eb.setDuration(readInt()); + break; + default: + mReader.skipValue(); + } + } + mReader.endObject(); + } catch (IllegalStateException ex) { + error("Error reading in object, ignoring.", ex); + consumeRemainingElements(); + mReader.endObject(); + continue; + } + e = eb.build(); + } + + return e; + } + + private ArrayList<Integer> readIntList() throws IOException { + ArrayList<Integer> data = new ArrayList<Integer>(); + try { + mReader.beginArray(); + while (mReader.hasNext()) { + data.add(Integer.decode(mReader.nextString())); + } + mReader.endArray(); + } catch (IllegalStateException | NumberFormatException e) { + consumeRemainingElements(); + mReader.endArray(); + throw new IllegalStateException("Encountered malformed data.", e); + } + return data; + } + + private byte[] readData() throws IOException { + ArrayList<Integer> data = readIntList(); + byte[] rawData = new byte[data.size()]; + for (int i = 0; i < data.size(); i++) { + int d = data.get(i); + if ((d & 0xFF) != d) { + throw new IllegalStateException("Invalid data, all values must be byte-sized"); + } + rawData[i] = (byte) d; + } + return rawData; + } + + private int readInt() throws IOException { + String val = mReader.nextString(); + return Integer.decode(val); + } + + private Bus readBus() throws IOException { + String val = mReader.nextString(); + return Bus.valueOf(val.toUpperCase()); + } + + private SparseArray<int[]> readConfiguration() + throws IllegalStateException, IOException { + SparseArray<int[]> configuration = new SparseArray<>(); + try { + mReader.beginArray(); + while (mReader.hasNext()) { + int type = 0; + int[] data = null; + mReader.beginObject(); + while (mReader.hasNext()) { + String name = mReader.nextName(); + switch (name) { + case "type": + type = readInt(); + break; + case "data": + data = readIntList().stream() + .mapToInt(Integer::intValue).toArray(); + break; + default: + consumeRemainingElements(); + mReader.endObject(); + throw new IllegalStateException( + "Invalid key in device configuration: " + name); + } + } + mReader.endObject(); + if (data != null) { + configuration.put(type, data); + } + } + mReader.endArray(); + } catch (IllegalStateException | NumberFormatException e) { + consumeRemainingElements(); + mReader.endArray(); + throw new IllegalStateException("Encountered malformed data.", e); + } + return configuration; + } + + private InputAbsInfo readAbsInfo() throws IllegalStateException, IOException { + InputAbsInfo absInfo = new InputAbsInfo(); + try { + mReader.beginObject(); + while (mReader.hasNext()) { + String name = mReader.nextName(); + switch (name) { + case "value": + absInfo.value = readInt(); + break; + case "minimum": + absInfo.minimum = readInt(); + break; + case "maximum": + absInfo.maximum = readInt(); + break; + case "fuzz": + absInfo.fuzz = readInt(); + break; + case "flat": + absInfo.flat = readInt(); + break; + case "resolution": + absInfo.resolution = readInt(); + break; + default: + consumeRemainingElements(); + mReader.endObject(); + throw new IllegalStateException("Invalid key in abs info: " + name); + } + } + mReader.endObject(); + } catch (IllegalStateException | NumberFormatException e) { + consumeRemainingElements(); + mReader.endObject(); + throw new IllegalStateException("Encountered malformed data.", e); + } + return absInfo; + } + + private SparseArray<InputAbsInfo> readAbsInfoArray() + throws IllegalStateException, IOException { + SparseArray<InputAbsInfo> infoArray = new SparseArray<>(); + try { + mReader.beginArray(); + while (mReader.hasNext()) { + int type = 0; + InputAbsInfo absInfo = null; + mReader.beginObject(); + while (mReader.hasNext()) { + String name = mReader.nextName(); + switch (name) { + case "code": + type = readInt(); + break; + case "info": + absInfo = readAbsInfo(); + break; + default: + consumeRemainingElements(); + mReader.endObject(); + throw new IllegalStateException("Invalid key in abs info array: " + + name); + } + } + mReader.endObject(); + if (absInfo != null) { + infoArray.put(type, absInfo); + } + } + mReader.endArray(); + } catch (IllegalStateException | NumberFormatException e) { + consumeRemainingElements(); + mReader.endArray(); + throw new IllegalStateException("Encountered malformed data.", e); + } + return infoArray; + } + + private void consumeRemainingElements() throws IOException { + while (mReader.hasNext()) { + mReader.skipValue(); + } + } + } + + private static void error(String msg, Exception e) { + System.out.println(msg); + Log.e(TAG, msg); + if (e != null) { + Log.e(TAG, Log.getStackTraceString(e)); + } + } +} diff --git a/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl new file mode 100644 index 000000000000..88c57f2c8965 --- /dev/null +++ b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl @@ -0,0 +1,26 @@ +/* +** +** Copyright 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. +*/ +package src.com.android.commands.uinput; + +parcelable InputAbsInfo { + int value; + int minimum; + int maximum; + int fuzz; + int flat; + int resolution; +} diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java new file mode 100644 index 000000000000..f7601a2f7c07 --- /dev/null +++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +package com.android.commands.uinput; + +import android.util.Log; +import android.util.SparseArray; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; + +/** + * Uinput class encapsulates execution of "uinput" command. It parses the provided input stream + * parameters as JSON file format, extract event entries and perform commands of event entries. + * Uinput device will be created when performing registration command and used to inject events. + */ +public class Uinput { + private static final String TAG = "UINPUT"; + + private final Event.Reader mReader; + private final SparseArray<Device> mDevices; + + private static void usage() { + error("Usage: uinput [FILE]"); + } + + /** + * Commandline "uinput" binary main entry + */ + public static void main(String[] args) { + if (args.length != 1) { + usage(); + System.exit(1); + } + + InputStream stream = null; + try { + if (args[0].equals("-")) { + stream = System.in; + } else { + File f = new File(args[0]); + stream = new FileInputStream(f); + } + (new Uinput(stream)).run(); + } catch (Exception e) { + error("Uinput injection failed.", e); + System.exit(1); + } finally { + try { + stream.close(); + } catch (IOException e) { + } + } + } + + private Uinput(InputStream in) { + mDevices = new SparseArray<Device>(); + try { + mReader = new Event.Reader(new InputStreamReader(in, "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private void run() { + try { + Event e = null; + while ((e = mReader.getNextEvent()) != null) { + process(e); + } + } catch (IOException ex) { + error("Error reading in events.", ex); + } + + for (int i = 0; i < mDevices.size(); i++) { + mDevices.valueAt(i).close(); + } + } + + private void process(Event e) { + final int index = mDevices.indexOfKey(e.getId()); + if (index >= 0) { + Device d = mDevices.valueAt(index); + if (Event.COMMAND_DELAY.equals(e.getCommand())) { + d.addDelay(e.getDuration()); + } else if (Event.COMMAND_INJECT.equals(e.getCommand())) { + d.injectEvent(e.getInjections()); + } else { + if (Event.COMMAND_REGISTER.equals(e.getCommand())) { + error("Device id=" + e.getId() + " is already registered. Ignoring event."); + } else { + error("Unknown command \"" + e.getCommand() + "\". Ignoring event."); + } + } + } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) { + registerDevice(e); + } else { + Log.e(TAG, "Unknown device id specified. Ignoring event."); + } + } + + private void registerDevice(Event e) { + if (!Event.COMMAND_REGISTER.equals(e.getCommand())) { + throw new IllegalStateException( + "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!"); + } + int id = e.getId(); + Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(), + e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo()); + mDevices.append(id, d); + } + + private static void error(String msg) { + error(msg, null); + } + + private static void error(String msg, Exception e) { + Log.e(TAG, msg); + if (e != null) { + Log.e(TAG, Log.getStackTraceString(e)); + } + } +} diff --git a/cmds/uinput/uinput b/cmds/uinput/uinput new file mode 100755 index 000000000000..ab2770ee2043 --- /dev/null +++ b/cmds/uinput/uinput @@ -0,0 +1,9 @@ +#!/system/bin/sh + +# Preload the native portion libuinputcommand_jni.so to bypass the dependency +# checks in the Java classloader, which prohibit dependencies that aren't +# listed in system/core/rootdir/etc/public.libraries.android.txt. +export LD_PRELOAD=libuinputcommand_jni.so + +export CLASSPATH=/system/framework/uinput.jar +exec app_process /system/bin com.android.commands.uinput.Uinput "$@" |