Merge "Surfaceflinger: Document DdmConnection usage"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 29589cd..d5620bf 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -39,6 +39,7 @@
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <hardware_legacy/power.h>
@@ -395,6 +396,81 @@
     }
 }
 
+/**
+ * Finds the last modified file in the directory dir whose name starts with file_prefix.
+ *
+ * Function returns empty string when it does not find a file
+ */
+static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
+                                                 const std::string& file_prefix) {
+    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
+    if (d == nullptr) {
+        MYLOGD("Error %d opening %s\n", errno, dir.c_str());
+        return "";
+    }
+
+    // Find the newest file matching the file_prefix in dir
+    struct dirent *de;
+    time_t last_modified_time = 0;
+    std::string last_modified_file = "";
+    struct stat s;
+
+    while ((de = readdir(d.get()))) {
+        std::string file = std::string(de->d_name);
+        if (!file_prefix.empty()) {
+            if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
+        }
+        file = dir + "/" + file;
+        int ret = stat(file.c_str(), &s);
+
+        if ((ret == 0) && (s.st_mtime > last_modified_time)) {
+            last_modified_file = file;
+            last_modified_time = s.st_mtime;
+        }
+    }
+
+    return last_modified_file;
+}
+
+static void DumpModemLogs() {
+    DurationReporter durationReporter("DUMP MODEM LOGS");
+    if (IsUserBuild()) {
+        return;
+    }
+
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
+        return;
+    }
+
+    std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
+
+    if(file_prefix.empty()) {
+        MYLOGD("No modem log : file_prefix is empty\n");
+        return;
+    }
+
+    // TODO: use bugreport_dir_ directly when this function is moved to Dumpstate class
+    std::string bugreport_dir = dirname(ds.GetPath("").c_str());
+    MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
+           bugreport_dir.c_str(), file_prefix.c_str());
+
+    std::string modem_log_file = GetLastModifiedFileWithPrefix(bugreport_dir, file_prefix);
+
+    struct stat s;
+    if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
+        MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
+        return;
+    }
+
+    std::string filename = basename(modem_log_file.c_str());
+    if (!ds.AddZipEntry(filename, modem_log_file)) {
+        MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
+    } else {
+        MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
+    }
+}
+
 static bool skip_not_stat(const char *path) {
     static const char stat[] = "/stat";
     size_t len = strlen(path);
@@ -1037,6 +1113,11 @@
 
     RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
 
+    // DumpModemLogs adds the modem logs if available to the bugreport.
+    // Do this at the end to allow for sufficient time for the modem logs to be
+    // collected.
+    DumpModemLogs();
+
     printf("========================================================\n");
     printf("== Final progress (pid %d): %d/%d (originally %d)\n", getpid(), ds.progress_,
            ds.weight_total_, WEIGHT_TOTAL);
diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk
index b87d34f..3cf1148 100644
--- a/cmds/surfacereplayer/proto/Android.mk
+++ b/cmds/surfacereplayer/proto/Android.mk
@@ -18,10 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-proto-files-under, src)
 
-LOCAL_SHARED_LIBRARIES := \
-    libprotobuf-cpp-full
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := full
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
 
 LOCAL_MODULE := libtrace_proto
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 45060af..0bc08a9 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -1,4 +1,5 @@
 syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
 
 message Trace {
     repeated Increment increment = 1;
diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
index dac4314..3ec3178 100644
--- a/cmds/surfacereplayer/replayer/Android.mk
+++ b/cmds/surfacereplayer/replayer/Android.mk
@@ -40,7 +40,8 @@
     libgui \
     libui \
     libutils \
-    libprotobuf-cpp-full \
+    libprotobuf-cpp-lite \
+    libbase \
 
 LOCAL_STATIC_LIBRARIES := \
     libtrace_proto \
@@ -57,7 +58,7 @@
     Main.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
-    libprotobuf-cpp-full \
+    libprotobuf-cpp-lite \
     libsurfacereplayer \
     libutils \
 
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index ace10d1..a49da37 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -20,6 +20,8 @@
 
 #include <android/native_window.h>
 
+#include <android-base/file.h>
+
 #include <binder/IMemory.h>
 
 #include <gui/BufferQueue.h>
@@ -61,14 +63,18 @@
         mStopTimeStamp(stopHere) {
     srand(RAND_COLOR_SEED);
 
-    std::fstream input(filename, std::ios::in | std::ios::binary);
-
-    mLoaded = mTrace.ParseFromIstream(&input);
-    if (!mLoaded) {
+    std::string input;
+    if (!android::base::ReadFileToString(filename, &input, true)) {
         std::cerr << "Trace did not load. Does " << filename << " exist?" << std::endl;
         abort();
     }
 
+    mLoaded = mTrace.ParseFromString(input);
+    if (!mLoaded) {
+        std::cerr << "Trace did not load." << std::endl;
+        abort();
+    }
+
     mCurrentTime = mTrace.increment(0).time_stamp();
 
     sReplayingManually.store(replayManually);
diff --git a/include/binder/TextOutput.h b/include/binder/TextOutput.h
index 0e9975a..851e01f 100644
--- a/include/binder/TextOutput.h
+++ b/include/binder/TextOutput.h
@@ -18,6 +18,7 @@
 #define ANDROID_TEXTOUTPUT_H
 
 #include <utils/Errors.h>
+#include <utils/String8.h>
 
 #include <stdint.h>
 #include <string.h>
@@ -26,9 +27,6 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
-class String8;
-class String16;
-
 class TextOutput
 {
 public:
@@ -121,6 +119,32 @@
 };
 
 TextOutput& operator<<(TextOutput& to, const HexDump& val);
+inline TextOutput& operator<<(TextOutput& to,
+                              decltype(std::endl<char,
+                                       std::char_traits<char>>)
+                              /*val*/) {
+    endl(to);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const char &c)
+{
+    to.print(&c, 1);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const bool &val)
+{
+    if (val) to.print("true", 4);
+    else to.print("false", 5);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const String16& val)
+{
+    to << String8(val).string();
+    return to;
+}
 
 // ---------------------------------------------------------------------------
 // No user servicable parts below.
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 4f77eed..2152206 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -51,3 +51,13 @@
         "-O3",
     ],
 }
+
+cc_test {
+    name: "binderTextOutputTest",
+    srcs: ["binderTextOutputTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libbase",
+    ],
+}
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index e02844e..ff5912f 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -229,7 +229,9 @@
             .sender_euid = 0,
             .data_size = 0,
             .offsets_size = 0,
-            .data = {0, 0},
+            .data = {
+                .ptr = {0, 0},
+            },
         },
     };
     struct {
@@ -350,4 +352,3 @@
 
     return RUN_ALL_TESTS();
 }
-
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index cb0e965..757291c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -34,6 +34,7 @@
 
 static testing::Environment* binder_env;
 static char *binderservername;
+static char *binderserversuffix;
 static char binderserverarg[] = "--binderserver";
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
@@ -72,6 +73,7 @@
         binderserverarg,
         stri,
         strpipefd1,
+        binderserversuffix,
         NULL
     };
 
@@ -969,6 +971,8 @@
 
 int run_server(int index, int readypipefd)
 {
+    binderLibTestServiceName += String16(binderserversuffix);
+
     status_t ret;
     sp<IServiceManager> sm = defaultServiceManager();
     {
@@ -999,15 +1003,19 @@
 int main(int argc, char **argv) {
     int ret;
 
-    if (argc == 3 && !strcmp(argv[1], "--servername")) {
+    if (argc == 4 && !strcmp(argv[1], "--servername")) {
         binderservername = argv[2];
     } else {
         binderservername = argv[0];
     }
 
-    if (argc == 4 && !strcmp(argv[1], binderserverarg)) {
+    if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
+        binderserversuffix = argv[4];
         return run_server(atoi(argv[2]), atoi(argv[3]));
     }
+    binderserversuffix = new char[16];
+    snprintf(binderserversuffix, 16, "%d", getpid());
+    binderLibTestServiceName += String16(binderserversuffix);
 
     ::testing::InitGoogleTest(&argc, argv);
     binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv());
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
new file mode 100644
index 0000000..f6dd22d
--- /dev/null
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits>
+#include <cstddef>
+
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <binder/TextOutput.h>
+#include <binder/Debug.h>
+
+static void CheckMessage(const CapturedStderr& cap,
+                         const char* expected,
+                         bool singleline) {
+    std::string output;
+    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+    android::base::ReadFdToString(cap.fd(), &output);
+    if (singleline)
+        output.erase(std::remove(output.begin(), output.end(), '\n'));
+    ASSERT_STREQ(output.c_str(), expected);
+}
+
+#define CHECK_LOG_(input, expect, singleline)    \
+{                                                \
+    CapturedStderr cap;                          \
+    android::aerr << input << android::endl;     \
+    CheckMessage(cap, expect, singleline);       \
+}                                                \
+
+#define CHECK_VAL_(val, singleline)              \
+{                                                \
+    std::stringstream ss;                        \
+    ss << val;                                   \
+    std::string s = ss.str();                    \
+    CHECK_LOG_(val, s.c_str(), singleline);      \
+}                                                \
+
+#define CHECK_LOG(input, expect) CHECK_LOG_(input, expect, true)
+#define CHECK_VAL(val) CHECK_VAL_(val, true)
+
+TEST(TextOutput, HandlesStdEndl) {
+    CapturedStderr cap;
+    android::aerr << "foobar" << std::endl;
+    std::string output;
+    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+    android::base::ReadFdToString(cap.fd(), &output);
+    ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandlesCEndl) {
+    CapturedStderr cap;
+    android::aerr << "foobar" << "\n";
+    std::string output;
+    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+    android::base::ReadFdToString(cap.fd(), &output);
+    ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandlesAndroidEndl) {
+    CapturedStderr cap;
+    android::aerr << "foobar" << android::endl;
+    std::string output;
+    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+    android::base::ReadFdToString(cap.fd(), &output);
+    ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandleEmptyString) {
+    CHECK_LOG("", "");
+}
+
+TEST(TextOutput, HandleString) {
+    CHECK_LOG("foobar", "foobar");
+}
+
+TEST(TextOutput, HandleNum) {
+    CHECK_LOG(12345, "12345");
+}
+
+TEST(TextOutput, HandleBool) {
+    CHECK_LOG(false, "false");
+}
+
+TEST(TextOutput, HandleChar) {
+    CHECK_LOG('T', "T");
+}
+
+TEST(TextOutput, HandleParcel) {
+    android::Parcel val;
+    CHECK_LOG(val, "Parcel(NULL)");
+}
+
+TEST(TextOutput, HandleHexDump) {
+    const char buf[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+    android::HexDump val(buf, sizeof(buf));
+    CHECK_LOG(val, "03020100 07060504 0b0a0908 0f0e0d0c '................'");
+}
+
+TEST(TextOutput, HandleHexDumpCustom) {
+    const char buf[4] = {0x11,0x22,0x33,0x44};
+    android::HexDump val(buf, sizeof(buf), 4);
+    CHECK_LOG(val, "11 22 33 44 '.\"3D'");
+}
+
+TEST(TextOutput, HandleTypeCode) {
+    android::TypeCode val(1234);
+    CHECK_LOG(val, "'\\x04\\xd2'");
+}
+
+TEST(TextOutput, HandleCookie) {
+    int32_t val = 321; //0x141
+    CHECK_LOG((void*)(long)val, "0x141");
+}
+
+TEST(TextOutput, HandleString8) {
+    android::String8 val("foobar");
+    CHECK_LOG(val, "foobar");
+}
+
+TEST(TextOutput, HandleString16) {
+    android::String16 val("foobar");
+    CHECK_LOG(val, "foobar");
+}
+
+template <typename T>
+class TextTest : public testing::Test {};
+
+typedef testing::Types<short, unsigned short,
+                       int, unsigned int,
+                       long, unsigned long,
+                       long long, unsigned long long,
+                       float, double, long double> TestTypes;
+TYPED_TEST_CASE(TextTest, TestTypes);
+
+TYPED_TEST(TextTest, TextMax)
+{
+    TypeParam max = std::numeric_limits<TypeParam>::max();
+    CHECK_VAL(max);
+}
+
+TYPED_TEST(TextTest, TestMin)
+{
+    TypeParam min = std::numeric_limits<TypeParam>::min();
+    CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestDenom)
+{
+    TypeParam min = std::numeric_limits<TypeParam>::denorm_min();
+    CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestEpsilon)
+{
+    TypeParam eps = std::numeric_limits<TypeParam>::epsilon();
+    CHECK_VAL(eps);
+}
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index f695edb..ba036dd 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -145,7 +145,7 @@
     libgui \
     libpowermanager \
     libvulkan \
-    libprotobuf-cpp-full \
+    libprotobuf-cpp-lite \
     libhidl \
     libhwbinder \
     libbase \
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 4ae3580..a12276a 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -20,6 +20,9 @@
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceInterceptor.h"
+
+#include <android-base/file.h>
+
 #include <cutils/log.h>
 
 #include <utils/Trace.h>
@@ -119,14 +122,18 @@
 
 status_t SurfaceInterceptor::writeProtoFileLocked() {
     ATRACE_CALL();
-    std::ofstream output(mOutputFileName, std::ios::out | std::ios::trunc | std::ios::binary);
-    // SerializeToOstream returns false when it's missing required data or when it could not write
+    std::string output;
+
     if (!mTrace.IsInitialized()) {
         return NOT_ENOUGH_DATA;
     }
-    if (!mTrace.SerializeToOstream(&output)) {
+    if (!mTrace.SerializeToString(&output)) {
         return PERMISSION_DENIED;
     }
+    if (!android::base::WriteStringToFile(output, mOutputFileName, true)) {
+        return PERMISSION_DENIED;
+    }
+
     return NO_ERROR;
 }