Map isolated uid to host uid when processing log event in statsD.

Test: added test case for isolated uid in Attribution e2e test.
Change-Id: I63d16ebee3e611b1ef0c910e5154cf27766cb330
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a9e0f23..1cfec32 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -25,6 +25,8 @@
 #include "guardrail/StatsdStats.h"
 #include "metrics/CountMetricProducer.h"
 #include "external/StatsPullerManager.h"
+#include "dimension.h"
+#include "field_util.h"
 #include "stats_util.h"
 #include "storage/StorageManager.h"
 
@@ -88,30 +90,56 @@
     }
 }
 
-// TODO: what if statsd service restarts? How do we know what logs are already processed before?
-void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-
-    StatsdStats::getInstance().noteAtomLogged(msg.GetTagId(), msg.GetTimestampNs() / NS_PER_SEC);
-    // pass the event to metrics managers.
-    for (auto& pair : mMetricsManagers) {
-        pair.second->onLogEvent(msg);
-        flushIfNecessaryLocked(msg.GetTimestampNs(), pair.first, *(pair.second));
+void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
+    std::vector<Field> uidFields;
+    findFields(
+        event->getFieldValueMap(),
+        buildAttributionUidFieldMatcher(event->GetTagId(), Position::ANY),
+        &uidFields);
+    for (size_t i = 0; i < uidFields.size(); ++i) {
+        DimensionsValue* value = event->findFieldValueOrNull(uidFields[i]);
+        if (value != nullptr && value->value_case() == DimensionsValue::ValueCase::kValueInt) {
+            const int uid = mUidMap->getHostUidOrSelf(value->value_int());
+            value->set_value_int(uid);
+        }
     }
+}
+
+void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) {
+    status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
+    bool is_create = event.GetBool(3, &err);
+    auto parent_uid = int(event.GetLong(1, &err2));
+    auto isolated_uid = int(event.GetLong(2, &err3));
+    if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
+        if (is_create) {
+            mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
+        } else {
+            mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
+        }
+    } else {
+        ALOGE("Failed to parse uid in the isolated uid change event.");
+    }
+}
+
+// TODO: what if statsd service restarts? How do we know what logs are already processed before?
+void StatsLogProcessor::OnLogEvent(LogEvent* event) {
+    std::lock_guard<std::mutex> lock(mMetricsMutex);
+    StatsdStats::getInstance().noteAtomLogged(
+        event->GetTagId(), event->GetTimestampNs() / NS_PER_SEC);
+
     // Hard-coded logic to update the isolated uid's in the uid-map.
     // The field numbers need to be currently updated by hand with atoms.proto
-    if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) {
-        status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
-        bool is_create = msg.GetBool(3, &err);
-        auto parent_uid = int(msg.GetLong(1, &err2));
-        auto isolated_uid = int(msg.GetLong(2, &err3));
-        if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
-            if (is_create) {
-                mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
-            } else {
-                mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
-            }
-        }
+    if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+        onIsolatedUidChangedEventLocked(*event);
+    } else {
+        // Map the isolated uid to host uid if necessary.
+        mapIsolatedUidToHostUidIfNecessaryLocked(event);
+    }
+
+    // pass the event to metrics managers.
+    for (auto& pair : mMetricsManagers) {
+        pair.second->onLogEvent(*event);
+        flushIfNecessaryLocked(event->GetTimestampNs(), pair.first, *(pair.second));
     }
 }
 
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index adc9161..09e10a1 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -38,7 +38,7 @@
                       const std::function<void(const ConfigKey&)>& sendBroadcast);
     virtual ~StatsLogProcessor();
 
-    void OnLogEvent(const LogEvent& event);
+    void OnLogEvent(LogEvent* event);
 
     void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
     void OnConfigRemoved(const ConfigKey& key);
@@ -46,7 +46,8 @@
     size_t GetMetricsSize(const ConfigKey& key) const;
 
     void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
-    void onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs, ConfigMetricsReportList* report);
+    void onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs,
+                      ConfigMetricsReportList* report);
 
     /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
     void onAnomalyAlarmFired(
@@ -79,6 +80,12 @@
     void flushIfNecessaryLocked(uint64_t timestampNs, const ConfigKey& key,
                                 MetricsManager& metricsManager);
 
+    // Maps the isolated uid in the log event to host uid if the log event contains uid fields.
+    void mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const;
+
+    // Handler over the isolated uid change event.
+    void onIsolatedUidChangedEventLocked(const LogEvent& event);
+
     // Function used to send a broadcast so that receiver for the config key can call getData
     // to retrieve the stored data.
     std::function<void(const ConfigKey& key)> mSendBroadcast;
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 45f1ea1..0ed1c1f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -695,7 +695,7 @@
     mConfigManager->Startup();
 }
 
-void StatsService::OnLogEvent(const LogEvent& event) {
+void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index c0424f3..8d29970 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -72,7 +72,7 @@
     /**
      * Called by LogReader when there's a log event to process.
      */
-    virtual void OnLogEvent(const LogEvent& event);
+    virtual void OnLogEvent(LogEvent* event);
 
     /**
      * Binder call for clients to request data for this configuration key.
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
index 45b3586..09499b6 100644
--- a/cmds/statsd/src/dimension.cpp
+++ b/cmds/statsd/src/dimension.cpp
@@ -19,7 +19,6 @@
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_internal.pb.h"
 #include "dimension.h"
-#include "field_util.h"
 
 
 namespace android {
@@ -220,33 +219,35 @@
 constexpr int UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 1;
 constexpr int TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 2;
 
-void buildAttributionUidFieldMatcher(const int tagId, const Position position,
-                                     FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    matcher->add_child()->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
-    FieldMatcher* child = matcher->mutable_child(0)->add_child();
-    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-}
-
-void buildAttributionTagFieldMatcher(const int tagId, const Position position,
-                                     FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    FieldMatcher* child = matcher->add_child();
+FieldMatcher buildAttributionUidFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    auto child = matcher.add_child();
     child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
     child->set_position(position);
-    child = child->add_child();
-    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
 }
 
-void buildAttributionFieldMatcher(const int tagId, const Position position,
-                                  FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    FieldMatcher* child = matcher->add_child();
+FieldMatcher buildAttributionTagFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    FieldMatcher* child = matcher.add_child();
     child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
     child->set_position(position);
-    child = child->add_child();
-    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
+}
+
+FieldMatcher buildAttributionFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    FieldMatcher* child = matcher.add_child();
+    child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
+    child->set_position(position);
+    child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
 }
 
 void DimensionsValueToString(const DimensionsValue& value, std::string *flattened) {
diff --git a/cmds/statsd/src/dimension.h b/cmds/statsd/src/dimension.h
index 5bb64a9..845c138 100644
--- a/cmds/statsd/src/dimension.h
+++ b/cmds/statsd/src/dimension.h
@@ -27,7 +27,6 @@
 namespace os {
 namespace statsd {
 
-
 // Returns the leaf node from the DimensionsValue proto. It assume that the input has only one
 // leaf node at most.
 const DimensionsValue* getSingleLeafValue(const DimensionsValue* value);
diff --git a/cmds/statsd/src/field_util.cpp b/cmds/statsd/src/field_util.cpp
index d10e167..4ff4f74 100644
--- a/cmds/statsd/src/field_util.cpp
+++ b/cmds/statsd/src/field_util.cpp
@@ -184,6 +184,7 @@
     }
 }
 
+namespace {
 void findFields(
        const FieldValueMap& fieldValueMap,
        const FieldMatcher& matcher,
@@ -287,9 +288,18 @@
     }
 }
 
+}  // namespace
+
+void findFields(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       std::vector<Field>* rootFields) {
+    return findFields(fieldValueMap, matcher, buildSimpleAtomField(matcher.field()), rootFields);
+}
+
 void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap) {
     std::vector<Field> rootFields;
-    findFields(*fieldValueMap, matcher, buildSimpleAtomField(matcher.field()), &rootFields);
+    findFields(*fieldValueMap, matcher, &rootFields);
     std::set<Field, FieldCmp> rootFieldSet(rootFields.begin(), rootFields.end());
     auto it = fieldValueMap->begin();
     while (it != fieldValueMap->end()) {
@@ -313,6 +323,11 @@
     return true;
 }
 
+bool IsAttributionUidField(const Field& field) {
+    return field.child_size() == 1 && field.child(0).field() == 1
+        && field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/field_util.h b/cmds/statsd/src/field_util.h
index 3e7d54c..a4dfddd 100644
--- a/cmds/statsd/src/field_util.h
+++ b/cmds/statsd/src/field_util.h
@@ -85,6 +85,9 @@
 // Filter out the fields not in the field matcher.
 void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap);
 
+// Returns if the field is attribution node uid field.
+bool IsAttributionUidField(const Field& field);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 49a6e33..6782f3f 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -397,6 +397,14 @@
     return dimensionsValue;
 }
 
+DimensionsValue* LogEvent::findFieldValueOrNull(const Field& field) {
+    auto it = mFieldValueMap.find(field);
+    if (it == mFieldValueMap.end()) {
+        return nullptr;
+    }
+    return &it->second;
+}
+
 string LogEvent::ToString() const {
     ostringstream result;
     result << "{ " << mTimestampNs << " (" << mTagId << ")";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 8f3dedf..fdfa32e 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -132,6 +132,11 @@
         return mFieldValueMap.size();
     }
 
+    /**
+     * Returns the mutable DimensionsValue proto for the specific the field.
+     */
+    DimensionsValue* findFieldValueOrNull(const Field& field);
+
     inline const FieldValueMap& getFieldValueMap() const { return mFieldValueMap; }
 
 private:
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
index 9641226..69ca571 100644
--- a/cmds/statsd/src/logd/LogListener.h
+++ b/cmds/statsd/src/logd/LogListener.h
@@ -33,7 +33,7 @@
     LogListener();
     virtual ~LogListener();
 
-    virtual void OnLogEvent(const LogEvent& msg) = 0;
+    virtual void OnLogEvent(LogEvent* msg) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/logd/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp
index c441a5e..7636268 100644
--- a/cmds/statsd/src/logd/LogReader.cpp
+++ b/cmds/statsd/src/logd/LogReader.cpp
@@ -110,7 +110,7 @@
             LogEvent event(msg);
 
             // Call the listener
-            mListener->OnLogEvent(event);
+            mListener->OnLogEvent(&event);
         }
     }
 
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 46d9b92..48f62e7 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -93,11 +93,6 @@
     return matched;
 }
 
-bool IsAttributionUidField(const Field& field) {
-    return field.child_size() == 1 && field.child(0).field() == 1
-        && field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
-}
-
 bool matchesNonRepeatedField(
        const UidMap& uidMap,
        const FieldValueMap& fieldMap,
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 517d21d..b0c3197 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -269,7 +269,7 @@
     }
 }
 
-int UidMap::getParentUidOrSelf(int uid) {
+int UidMap::getHostUidOrSelf(int uid) const {
     lock_guard<mutex> lock(mIsolatedMutex);
 
     auto it = mIsolatedUidMap.find(uid);
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 07e13e0..4e37977 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -90,8 +90,8 @@
     void assignIsolatedUid(int isolatedUid, int parentUid);
     void removeIsolatedUid(int isolatedUid, int parentUid);
 
-    // Returns the parent uid if it exists. Otherwise, returns the same uid that was passed-in.
-    int getParentUidOrSelf(int uid);
+    // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
+    int getHostUidOrSelf(int uid) const;
 
     // Gets the output. If every config key has received the output, then the output is cleared.
     UidMapping getOutput(const ConfigKey& key);
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 945af27..5292f24 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -45,18 +45,18 @@
     addEvent.write(1);    // Indicates creation.
     addEvent.init();
 
-    EXPECT_EQ(101, m->getParentUidOrSelf(101));
+    EXPECT_EQ(101, m->getHostUidOrSelf(101));
 
-    p.OnLogEvent(addEvent);
-    EXPECT_EQ(100, m->getParentUidOrSelf(101));
+    p.OnLogEvent(&addEvent);
+    EXPECT_EQ(100, m->getHostUidOrSelf(101));
 
     LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
     removeEvent.write(100);  // parent UID
     removeEvent.write(101);  // isolated UID
     removeEvent.write(0);    // Indicates removal.
     removeEvent.init();
-    p.OnLogEvent(removeEvent);
-    EXPECT_EQ(101, m->getParentUidOrSelf(101));
+    p.OnLogEvent(&removeEvent);
+    EXPECT_EQ(101, m->getHostUidOrSelf(101));
 }
 
 TEST(UidMapTest, TestMatching) {
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index e28dd31..39c9549 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -106,6 +106,10 @@
         {CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
     std::vector<AttributionNode> attributions8 = {CreateAttribution(111, "App1")};
 
+    // GMS core node with isolated uid.
+    const int isolatedUid = 666;
+    std::vector<AttributionNode> attributions9 =
+        {CreateAttribution(isolatedUid, "GMSCoreModule3")};
 
     std::vector<std::unique_ptr<LogEvent>> events;
     // Events 1~4 are in the 1st bucket.
@@ -124,22 +128,30 @@
     events.push_back(CreateAcquireWakelockEvent(
         attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
     events.push_back(CreateAcquireWakelockEvent(
-        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 1));
+        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
     events.push_back(CreateAcquireWakelockEvent(
         attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
 
     sortLogEventsByTimestamp(&events);
 
     for (const auto& event : events) {
-        processor->OnLogEvent(*event);
+        processor->OnLogEvent(event.get());
     }
     ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs + 1, &reports);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &reports);
     EXPECT_EQ(reports.reports_size(), 1);
     EXPECT_EQ(reports.reports(0).metrics_size(), 1);
     StatsLogReport::CountMetricDataWrapper countMetrics;
     sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    EXPECT_EQ(countMetrics.data_size(), 3);
+    EXPECT_EQ(countMetrics.data_size(), 4);
 
     auto data = countMetrics.data(0);
     ValidateAttributionUidAndTagDimension(
@@ -165,6 +177,14 @@
 
     data = countMetrics.data(2);
     ValidateAttributionUidAndTagDimension(
+        data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+
+    data = countMetrics.data(3);
+    ValidateAttributionUidAndTagDimension(
         data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index a81bbb9..cdc4467 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -188,7 +188,7 @@
     sortLogEventsByTimestamp(&events);
 
     for (const auto& event : events) {
-        processor->OnLogEvent(*event);
+        processor->OnLogEvent(event.get());
     }
     ConfigMetricsReportList reports;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 47e8a72..2783356 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -107,7 +107,7 @@
         sortLogEventsByTimestamp(&events);
 
         for (const auto& event : events) {
-            processor->OnLogEvent(*event);
+            processor->OnLogEvent(event.get());
         }
 
         ConfigMetricsReportList reports;
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index f9ac6d6..e788235 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -292,6 +292,17 @@
         uid, ProcessLifeCycleStateChanged::PROCESS_CRASHED, timestampNs);
 }
 
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
+    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
+    auto logEvent = std::make_unique<LogEvent>(
+        android::util::ISOLATED_UID_CHANGED, timestampNs);
+    logEvent->write(hostUid);
+    logEvent->write(isolatedUid);
+    logEvent->write(is_create);
+    logEvent->init();
+    return logEvent;
+}
+
 sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
                                               const ConfigKey& key) {
     sp<UidMap> uidMap = new UidMap();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index f1ce358..1bbbd9a 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -111,6 +111,10 @@
     const std::vector<AttributionNode>& attributions,
     const string& wakelockName, uint64_t timestampNs);
 
+// Create log event for releasing wakelock.
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
+    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+
 // Helper function to create an AttributionNode proto.
 AttributionNode CreateAttribution(const int& uid, const string& tag);