Merge "Cleanup package_string() and its users"
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index cd5d7d4..3fc5e5d 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1082,50 +1082,45 @@
     }
 
     if (printStatistics || getPruneList) {
-        size_t len = 8192;
-        char* buf;
+        std::string buf(8192, '\0');
+        size_t ret_length = 0;
+        int retry = 32;
 
-        for (int retry = 32; (retry >= 0) && ((buf = new char[len]));
-             delete[] buf, buf = nullptr, --retry) {
+        for (; retry >= 0; --retry) {
             if (getPruneList) {
-                android_logger_get_prune_list(logger_list.get(), buf, len);
+                android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
             } else {
-                android_logger_get_statistics(logger_list.get(), buf, len);
+                android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
             }
-            buf[len - 1] = '\0';
-            if (atol(buf) < 3) {
-                delete[] buf;
-                buf = nullptr;
+
+            ret_length = atol(buf.c_str());
+            if (ret_length < 3) {
+                error(EXIT_FAILURE, 0, "Failed to read data.");
+            }
+
+            if (ret_length < buf.size()) {
                 break;
             }
-            size_t ret = atol(buf) + 1;
-            if (ret <= len) {
-                len = ret;
-                break;
-            }
-            len = ret;
+
+            buf.resize(ret_length + 1);
         }
 
-        if (!buf) {
+        if (retry < 0) {
             error(EXIT_FAILURE, 0, "Failed to read data.");
         }
 
-        // remove trailing FF
-        char* cp = buf + len - 1;
-        *cp = '\0';
-        bool truncated = *--cp != '\f';
-        if (!truncated) *cp = '\0';
-
-        // squash out the byte count
-        cp = buf;
-        if (!truncated) {
-            while (isdigit(*cp)) ++cp;
-            if (*cp == '\n') ++cp;
+        buf.resize(ret_length);
+        if (buf.back() == '\f') {
+            buf.pop_back();
         }
 
-        len = strlen(cp);
+        // Remove the byte count prefix
+        const char* cp = buf.c_str();
+        while (isdigit(*cp)) ++cp;
+        if (*cp == '\n') ++cp;
+
+        size_t len = strlen(cp);
         TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
-        delete[] buf;
         return EXIT_SUCCESS;
     }
 
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 7a843d8..694b5fa 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h>
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <string.h>
@@ -186,14 +187,26 @@
     : LogCommand("getStatistics"), mBuf(*buf) {
 }
 
-static std::string package_string(const std::string& str) {
-    // Calculate total buffer size prefix, count is the string length w/o nul
-    char fmt[32];
-    for (size_t l = str.length(), y = 0, x = 6; y != x;
-         y = x, x = strlen(fmt) - 2) {
-        snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
+// This returns a string with a length prefix with the format <length>\n<data>\n\f.  The length
+// prefix includes the length of the prefix itself.
+static std::string PackageString(const std::string& str) {
+    size_t overhead_length = 3;  // \n \n \f.
+
+    // Number of digits needed to represent length(str + overhead_length).
+    size_t str_size_digits = 1 + static_cast<size_t>(log10(str.size() + overhead_length));
+    // Number of digits needed to represent the total size.
+    size_t total_size_digits =
+            1 + static_cast<size_t>(log10(str.size() + overhead_length + str_size_digits));
+
+    // If adding the size prefix causes a new digit to be required to represent the new total
+    // size, add it to the 'overhead_length'.  This can only happen once, since each new digit
+    // allows for 10x the previous size to be recorded.
+    if (total_size_digits != str_size_digits) {
+        overhead_length++;
     }
-    return android::base::StringPrintf(fmt, str.c_str());
+
+    size_t total_size = str.size() + overhead_length + str_size_digits;
+    return android::base::StringPrintf("%zu\n%s\n\f", total_size, str.c_str());
 }
 
 int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
@@ -228,8 +241,7 @@
         }
     }
 
-    cli->sendMsg(
-        package_string(mBuf.formatStatistics(uid, pid, logMask)).c_str());
+    cli->sendMsg(PackageString(mBuf.formatStatistics(uid, pid, logMask)).c_str());
     return 0;
 }
 
@@ -240,7 +252,7 @@
 int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
                                                  int /*argc*/, char** /*argv*/) {
     setname();
-    cli->sendMsg(package_string(mBuf.formatPrune()).c_str());
+    cli->sendMsg(PackageString(mBuf.formatPrune()).c_str());
     return 0;
 }
 
@@ -316,12 +328,11 @@
             cli->sendMsg("can not mix id= with either format= or name=");
             return 0;
         }
-        cli->sendMsg(package_string(mBuf.formatEntry(atoi(id), uid)).c_str());
+        cli->sendMsg(PackageString(mBuf.formatEntry(atoi(id), uid)).c_str());
         return 0;
     }
 
-    cli->sendMsg(
-        package_string(mBuf.formatGetEventTag(uid, name, format)).c_str());
+    cli->sendMsg(PackageString(mBuf.formatGetEventTag(uid, name, format)).c_str());
 
     return 0;
 }