OSDN Git Service

Fix recovery of stats data from previous input while using
authoryro <yro@google.com>
Fri, 16 Mar 2018 02:42:05 +0000 (19:42 -0700)
committeryro <yro@google.com>
Tue, 20 Mar 2018 22:00:59 +0000 (15:00 -0700)
ProtoOutputStream

- Specify the length of message to avoid libprotoutil from thinking that
we are trying to write bool
- We only attach the previous dump file to the upload file where config
key matches
- Store ConfigMetricsReport (instead of ConfigMetricsReportList) onto
disk
- Stop use stack after scope in StorageManager
- Migrate UidMap to use ProtoOutputStream and renaming variables to
prevent confusion

Bug: 74021554
Bug: 75968524
Test: manual test, statsd_test, CTS tests
Change-Id: Iedf52633d7f5b985f5a934a3fb5a0c3c3b2e7fd1

cmds/statsd/src/StatsLogProcessor.cpp
cmds/statsd/src/StatsLogProcessor.h
cmds/statsd/src/packages/UidMap.cpp
cmds/statsd/src/packages/UidMap.h
cmds/statsd/src/storage/StorageManager.cpp
cmds/statsd/src/storage/StorageManager.h
cmds/statsd/tests/UidMap_test.cpp

index 652ec9d..4a1e3d6 100644 (file)
@@ -231,14 +231,13 @@ void StatsLogProcessor::dumpStates(FILE* out, bool verbose) {
     }
 }
 
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
 void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t dumpTimeStampNs,
                                      vector<uint8_t>* outData) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    onDumpReportLocked(key, dumpTimeStampNs, outData);
-}
 
-void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
-                                           vector<uint8_t>* outData) {
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end()) {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
@@ -261,35 +260,14 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
     // Start of ConfigMetricsReport (reports).
     uint64_t reportsToken =
             proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
-
-    int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
-    int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
-
-    // First, fill in ConfigMetricsReport using current data on memory, which
-    // starts from filling in StatsLogReport's.
-    it->second->onDumpReport(dumpTimeStampNs, &proto);
-
-    // Fill in UidMap.
-    vector<uint8_t> uidMap;
-    mUidMap->getOutput(key, &uidMap);
-    proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMap.data());
-
-    // Fill in the timestamps.
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
-                (long long)lastReportTimeNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
-                (long long)dumpTimeStampNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
-                (long long)lastReportWallClockNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
-                (long long)getWallClockNs());
-
-    // End of ConfigMetricsReport (reports).
+    onConfigMetricsReportLocked(key, dumpTimeStampNs, &proto);
     proto.end(reportsToken);
+    // End of ConfigMetricsReport (reports).
+
 
     // Then, check stats-data directory to see there's any file containing
     // ConfigMetricsReport from previous shutdowns to concatenate to reports.
-    StorageManager::appendConfigMetricsReport(proto);
+    StorageManager::appendConfigMetricsReport(key, &proto);
 
     if (outData != nullptr) {
         outData->clear();
@@ -307,6 +285,40 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
     StatsdStats::getInstance().noteMetricsReportSent(key);
 }
 
+/*
+ * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
+ */
+void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
+                                                    const uint64_t dumpTimeStampNs,
+                                                    ProtoOutputStream* proto) {
+    // We already checked whether key exists in mMetricsManagers in
+    // WriteDataToDisk.
+    auto it = mMetricsManagers.find(key);
+    int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
+    int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
+
+    // First, fill in ConfigMetricsReport using current data on memory, which
+    // starts from filling in StatsLogReport's.
+    it->second->onDumpReport(dumpTimeStampNs, proto);
+
+    // Fill in UidMap.
+    uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
+    mUidMap->appendUidMap(key, proto);
+    proto->end(uidMapToken);
+
+    // Fill in the timestamps.
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+                (long long)lastReportTimeNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+                (long long)dumpTimeStampNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
+                (long long)lastReportWallClockNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
+                (long long)getWallClockNs());
+
+
+}
+
 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     auto it = mMetricsManagers.find(key);
@@ -360,11 +372,17 @@ void StatsLogProcessor::WriteDataToDisk() {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     for (auto& pair : mMetricsManagers) {
         const ConfigKey& key = pair.first;
-        vector<uint8_t> data;
-        onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
+        ProtoOutputStream proto;
+        onConfigMetricsReportLocked(key, getElapsedRealtimeNs(), &proto);
         string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
              (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
-        StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
+        android::base::unique_fd fd(open(file_name.c_str(),
+                                    O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+        if (fd == -1) {
+            VLOG("Attempt to write %s but failed", file_name.c_str());
+            return;
+        }
+        proto.flush(fd.get());
     }
 }
 
index 8b42146..1be4dc5 100644 (file)
@@ -86,8 +86,8 @@ private:
 
     sp<AlarmMonitor> mPeriodicAlarmMonitor;
 
-    void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs,
-                            vector<uint8_t>* outData);
+    void onConfigMetricsReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
+                                     util::ProtoOutputStream* proto);
 
     /* Check if we should send a broadcast if approaching memory limits and if we're over, we
      * actually delete the data. */
index efbe96e..3d07c44 100644 (file)
@@ -331,25 +331,25 @@ size_t UidMap::getBytesUsed() const {
     return mBytesUsed;
 }
 
-void UidMap::getOutput(const ConfigKey& key, vector<uint8_t>* outData) {
-    getOutput(getElapsedRealtimeNs(), key, outData);
+void UidMap::appendUidMap(const ConfigKey& key, ProtoOutputStream* proto) {
+    appendUidMap(getElapsedRealtimeNs(), key, proto);
 }
 
-void UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key, vector<uint8_t>* outData) {
+void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+                          ProtoOutputStream* proto) {
     lock_guard<mutex> lock(mMutex);  // Lock for updates
 
-    ProtoOutputStream proto;
     for (const ChangeRecord& record : mChanges) {
         if (record.timestampNs > mLastUpdatePerConfigKey[key]) {
             uint64_t changesToken =
-                    proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES);
-            proto.write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
-            proto.write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
-                        (long long)record.timestampNs);
-            proto.write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
-            proto.end(changesToken);
+                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES);
+            proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
+                         (long long)record.timestampNs);
+            proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
+            proto->end(changesToken);
         }
     }
 
@@ -360,13 +360,13 @@ void UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key, vector<ui
         if ((count == mSnapshots.size() - 1 && !atLeastOneSnapshot) ||
             record.timestampNs > mLastUpdatePerConfigKey[key]) {
             uint64_t snapshotsToken =
-                    proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
+                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
             atLeastOneSnapshot = true;
             count++;
-            proto.write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
-                        (long long)record.timestampNs);
-            proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
-            proto.end(snapshotsToken);
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
+                         (long long)record.timestampNs);
+            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
+            proto->end(snapshotsToken);
         }
     }
 
@@ -395,47 +395,36 @@ void UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key, vector<ui
             // Produce another snapshot. This results in extra data being uploaded but
             // helps ensure we can re-construct the UID->app name, versionCode mapping
             // in server.
-            ProtoOutputStream proto;
-            uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+            ProtoOutputStream snapshotProto;
+            uint64_t token = snapshotProto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                 FIELD_ID_SNAPSHOT_PACKAGE_INFO);
             for (const auto& it : mMap) {
-                proto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME,
-                            it.second.packageName);
-                proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
-                            (int)it.second.versionCode);
-                proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, (int)it.first);
+                snapshotProto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME,
+                                    it.second.packageName);
+                snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
+                                    (int)it.second.versionCode);
+                snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID,
+                                    (int)it.first);
             }
-            proto.end(token);
+            snapshotProto.end(token);
 
             // Copy ProtoOutputStream output to
-            auto iter = proto.data();
-            vector<char> outData(proto.size());
+            auto iter = snapshotProto.data();
+            vector<char> snapshotData(snapshotProto.size());
             size_t pos = 0;
             while (iter.readBuffer() != NULL) {
                 size_t toRead = iter.currentToRead();
-                std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+                std::memcpy(&(snapshotData[pos]), iter.readBuffer(), toRead);
                 pos += toRead;
                 iter.rp()->move(toRead);
             }
-            mSnapshots.emplace_back(timestamp, outData);
-            mBytesUsed += kBytesTimestampField + outData.size();
+            mSnapshots.emplace_back(timestamp, snapshotData);
+            mBytesUsed += kBytesTimestampField + snapshotData.size();
         }
     }
     StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
     StatsdStats::getInstance().setUidMapChanges(mChanges.size());
     StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
-    if (outData != nullptr) {
-        outData->clear();
-        outData->resize(proto.size());
-        size_t pos = 0;
-        auto iter = proto.data();
-        while (iter.readBuffer() != NULL) {
-            size_t toRead = iter.currentToRead();
-            std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead);
-            pos += toRead;
-            iter.rp()->move(toRead);
-        }
-    }
 }
 
 void UidMap::printUidMap(FILE* out) const {
index b0181f7..9dc73f4 100644 (file)
@@ -19,6 +19,7 @@
 #include "config/ConfigKey.h"
 #include "config/ConfigListener.h"
 #include "packages/PackageInfoListener.h"
+#include "stats_util.h"
 
 #include <binder/IResultReceiver.h>
 #include <binder/IShellCallback.h>
 #include <string>
 #include <unordered_map>
 
+using namespace android;
 using namespace std;
 
+using android::util::ProtoOutputStream;
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -45,8 +49,8 @@ struct AppData {
     AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
 };
 
-// When calling getOutput, we retrieve all the ChangeRecords since the last
-// timestamp we called getOutput for this configuration key.
+// When calling appendUidMap, we retrieve all the ChangeRecords since the last
+// timestamp we called appendUidMap for this configuration key.
 struct ChangeRecord {
     const bool deletion;
     const int64_t timestampNs;
@@ -70,8 +74,8 @@ const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord);
 // less because of varint encoding).
 const unsigned int kBytesTimestampField = 10;
 
-// When calling getOutput, we retrieve all the snapshots since the last
-// timestamp we called getOutput for this configuration key.
+// When calling appendUidMap, we retrieve all the snapshots since the last
+// timestamp we called appendUidMap for this configuration key.
 struct SnapshotRecord {
     const int64_t timestampNs;
 
@@ -135,7 +139,7 @@ public:
     // Gets all snapshots and changes that have occurred since the last output.
     // If every config key has received a change or snapshot record, then this
     // record is deleted.
-    void getOutput(const ConfigKey& key, vector<uint8_t>* outData);
+    void appendUidMap(const ConfigKey& key, util::ProtoOutputStream* proto);
 
     // Forces the output to be cleared. We still generate a snapshot based on the current state.
     // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
@@ -158,7 +162,8 @@ private:
                    const int64_t& versionCode);
     void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
 
-    void getOutput(const int64_t& timestamp, const ConfigKey& key, vector<uint8_t>* outData);
+    void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+                      util::ProtoOutputStream* proto);
 
     void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
 
index cd41f53..3d8aa47 100644 (file)
@@ -160,38 +160,46 @@ void StorageManager::sendBroadcast(const char* path,
     }
 }
 
-void StorageManager::appendConfigMetricsReport(ProtoOutputStream& proto) {
+void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto) {
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
     if (dir == NULL) {
         VLOG("Path %s does not exist", STATS_DATA_DIR);
         return;
     }
 
+    const char* suffix =
+            StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()).c_str();
+
     dirent* de;
     while ((de = readdir(dir.get()))) {
         char* name = de->d_name;
         if (name[0] == '.') continue;
-        VLOG("file %s", name);
 
-        int64_t result[3];
-        parseFileName(name, result);
-        if (result[0] == -1) continue;
-        int64_t timestamp = result[0];
-        int64_t uid = result[1];
-        int64_t configID = result[2];
-        string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
-        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string content;
-            if (android::base::ReadFdToString(fd, &content)) {
-                proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
-                            content.c_str());
+        size_t nameLen = strlen(name);
+        size_t suffixLen = strlen(suffix);
+        if (suffixLen <= nameLen &&
+                strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
+            int64_t result[3];
+            parseFileName(name, result);
+            if (result[0] == -1) continue;
+            int64_t timestamp = result[0];
+            int64_t uid = result[1];
+            int64_t configID = result[2];
+
+            string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
+            int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+            if (fd != -1) {
+                string content;
+                if (android::base::ReadFdToString(fd, &content)) {
+                    proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
+                                content.c_str(), content.size());
+                }
+                close(fd);
             }
-            close(fd);
-        }
 
-        // Remove file from disk after reading.
-        remove(file_name.c_str());
+            // Remove file from disk after reading.
+            remove(file_name.c_str());
+        }
     }
 }
 
@@ -275,9 +283,11 @@ bool StorageManager::hasIdenticalConfig(const ConfigKey& key,
                 if (android::base::ReadFdToString(fd, &content)) {
                     vector<uint8_t> vec(content.begin(), content.end());
                     if (vec == config) {
+                        close(fd);
                         return true;
                     }
                 }
+                close(fd);
             }
         }
     }
index 4b75628..fb7b085 100644 (file)
@@ -66,7 +66,7 @@ public:
      * Appends ConfigMetricsReport found on disk to the specific proto and
      * delete it.
      */
-    static void appendConfigMetricsReport(ProtoOutputStream& proto);
+    static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto);
 
     /**
      * Call to load the saved configs from disk.
index ee7d770..c9492eb 100644 (file)
@@ -20,6 +20,7 @@
 #include "statslog.h"
 #include "statsd_test_util.h"
 
+#include <android/util/ProtoOutputStream.h>
 #include <gtest/gtest.h>
 
 #include <stdio.h>
@@ -30,6 +31,8 @@ namespace android {
 namespace os {
 namespace statsd {
 
+using android::util::ProtoOutputStream;
+
 #ifdef __ANDROID__
 const string kApp1 = "app1.sharing.1";
 const string kApp2 = "app2.sharing.1";
@@ -156,6 +159,20 @@ TEST(UidMapTest, TestUpdateApp) {
     EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
 }
 
+static void protoOutputStreamToUidMapping(ProtoOutputStream* proto, UidMapping* results) {
+    vector<uint8_t> bytes;
+    bytes.resize(proto->size());
+    size_t pos = 0;
+    auto iter = proto->data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&((bytes)[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+    results->ParseFromArray(bytes.data(), bytes.size());
+}
+
 TEST(UidMapTest, TestClearingOutput) {
     UidMap m;
 
@@ -176,26 +193,26 @@ TEST(UidMapTest, TestClearingOutput) {
     m.updateMap(1, uids, versions, apps);
     EXPECT_EQ(1U, m.mSnapshots.size());
 
-    vector<uint8_t> bytes;
-    m.getOutput(2, config1, &bytes);
+    ProtoOutputStream proto;
+    m.appendUidMap(2, config1, &proto);
     UidMapping results;
-    results.ParseFromArray(bytes.data(), bytes.size());
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
 
     // It should be cleared now
     EXPECT_EQ(1U, m.mSnapshots.size());
-    bytes.clear();
-    m.getOutput(2, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(2, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
 
     // Now add another configuration.
     m.OnConfigUpdated(config2);
     m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
     EXPECT_EQ(1U, m.mChanges.size());
-    bytes.clear();
-    m.getOutput(6, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(6, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(1, results.changes_size());
     EXPECT_EQ(1U, m.mChanges.size());
@@ -205,16 +222,16 @@ TEST(UidMapTest, TestClearingOutput) {
     EXPECT_EQ(2U, m.mChanges.size());
 
     // We still can't remove anything.
-    bytes.clear();
-    m.getOutput(8, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(8, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(1, results.changes_size());
     EXPECT_EQ(2U, m.mChanges.size());
 
-    bytes.clear();
-    m.getOutput(9, config2, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(9, config2, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(2, results.changes_size());
     // At this point both should be cleared.
@@ -242,11 +259,12 @@ TEST(UidMapTest, TestMemoryComputed) {
     m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
     EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
 
+    ProtoOutputStream proto;
     vector<uint8_t> bytes;
-    m.getOutput(2, config1, &bytes);
+    m.appendUidMap(2, config1, &proto);
     size_t prevBytes = m.mBytesUsed;
 
-    m.getOutput(4, config1, &bytes);
+    m.appendUidMap(4, config1, &proto);
     EXPECT_TRUE(m.mBytesUsed < prevBytes);
 }
 
@@ -286,4 +304,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android