Merge "Prevent readTrainInfo from crashing statsd."
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 5df8fb5..65b183c 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -116,14 +116,16 @@
     const size_t trainNameSizeByteCount = sizeof(trainNameSize);
     result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
     if (result != trainNameSizeByteCount) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write train name size for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
     // Write trainName to file
     result = write(fd, trainName.c_str(), trainNameSize);
     if (result != trainNameSize) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write train name for%s", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -131,7 +133,18 @@
     const size_t statusByteCount = sizeof(status);
     result = write(fd, (uint8_t*)&status, statusByteCount);
     if (result != statusByteCount) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write status for %s", file_name.c_str());
+        close(fd);
+        return false;
+    }
+
+    // Write experiment id size to file.
+    const size_t experimentIdSize = experimentIds.size();
+    const size_t experimentIdsSizeByteCount = sizeof(experimentIdSize);
+    result = write(fd, (uint8_t*) &experimentIdSize, experimentIdsSizeByteCount);
+    if (result != experimentIdsSizeByteCount) {
+        VLOG("Failed to write experiment id size for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -140,13 +153,15 @@
     if (result == experimentIds.size()) {
         VLOG("Successfully wrote %s", file_name.c_str());
     } else {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write experiment ids for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
     result = fchown(fd, AID_STATSD, AID_STATSD);
     if (result) {
         VLOG("Failed to chown %s to statsd", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -170,39 +185,73 @@
         if (name[0] == '.') {
             continue;
         }
+
+        size_t result;
+
         trainInfo.trainVersionCode = StrToInt64(name);
         string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name);
         int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string str;
-            if (android::base::ReadFdToString(fd, &str)) {
-                close(fd);
-
-                auto it = str.begin();
-
-                // Read # of bytes taken by trainName in the file
-                size_t trainNameSize;
-                const size_t trainNameSizeByteCount = sizeof(trainNameSize);
-                std::copy_n(it, trainNameSizeByteCount, &trainNameSize);
-                it += trainNameSizeByteCount;
-
-                // Read trainName
-                std::copy_n(it, trainNameSize, std::back_inserter(trainInfo.trainName));
-                it += trainNameSize;
-
-                // Read status
-                const size_t statusByteCount = sizeof(trainInfo.status);
-                std::copy_n(it, statusByteCount, &trainInfo.status);
-                it += statusByteCount;
-
-                // Read experimentIds
-                std::copy(it, str.end(), std::back_inserter(trainInfo.experimentIds));
-
-                VLOG("Read train info file successful: %s", fullPath.c_str());
-                return true;
-            }
+        if (fd == -1) {
+            return false;
         }
+
+        // Read # of bytes taken by trainName in the file.
+        size_t trainNameSize;
+        result = read(fd, &trainNameSize, sizeof(size_t));
+        if (result != sizeof(size_t)) {
+            VLOG("Failed to read train name size from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read trainName
+        trainInfo.trainName.resize(trainNameSize);
+        result = read(fd, trainInfo.trainName.data(), trainNameSize);
+        if (result != trainNameSize) {
+            VLOG("Failed to read train name from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read status
+        const size_t statusByteCount = sizeof(trainInfo.status);
+        result = read(fd, &trainInfo.status, statusByteCount);
+        if (result != statusByteCount) {
+            VLOG("Failed to read train status from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read experiment ids size.
+        size_t experimentIdSize;
+        result = read(fd, &experimentIdSize, sizeof(size_t));
+        if (result != sizeof(size_t)) {
+            VLOG("Failed to read train experiment id size from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read experimentIds
+        trainInfo.experimentIds.resize(experimentIdSize);
+        result = read(fd, trainInfo.experimentIds.data(), experimentIdSize);
+        if (result != experimentIdSize) {
+            VLOG("Failed to read train experiment ids from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Expect to be at EOF.
+        char c;
+        result = read(fd, &c, 1);
+        if (result != 0) {
+            VLOG("Failed to read train info from file %s. Did not get expected EOF.", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        VLOG("Read train info file successful: %s", fullPath.c_str());
         close(fd);
+        return true;
     }
     return false;
 }