Merge "Update shell open command to have a mode."
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 5149b7f..83e30a2 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -176,7 +176,6 @@
             }
         }
     }
-    close(fd);
 
     if (!newline) dprintf(out_fd, "\n");
     if (!title.empty()) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index ea7109b..ede4254 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <log/log.h>
 
 #include "DumpstateInternal.h"
@@ -182,8 +183,8 @@
 }
 
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
-    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+    if (fd.get() < 0) {
         int err = errno;
         if (title.empty()) {
             dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err));
@@ -194,7 +195,7 @@
         fsync(out_fd);
         return -1;
     }
-    return DumpFileFromFdToFd(title, path, fd, out_fd, PropertiesHelper::IsDryRun());
+    return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
 }
 
 int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0d3cb32..380921d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -207,20 +207,36 @@
         const std::string& name = it->name;
         const int fd = it->fd;
         dumped = true;
+
+        // Seek to the beginning of the file before dumping any data. A given
+        // DumpData entry might be dumped multiple times in the report.
+        //
+        // For example, the most recent ANR entry is dumped to the body of the
+        // main entry and it also shows up as a separate entry in the bugreport
+        // ZIP file.
+        if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
+            MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
+                   strerror(errno));
+        }
+
         if (ds.IsZipping() && add_to_zip) {
             if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
-                MYLOGE("Unable to add %s %s to zip file\n", name.c_str(), type_name);
+                MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
             }
         } else {
             dump_file_from_fd(type_name, name.c_str(), fd);
         }
-
-        close(fd);
     }
 
     return dumped;
 }
 
+static void CloseDumpFds(const std::vector<DumpData>* dumps) {
+    for (auto it = dumps->begin(); it != dumps->end(); ++it) {
+        close(it->fd);
+    }
+}
+
 // for_each_pid() callback to get mount info about a process.
 void do_mountinfo(int pid, const char* name __attribute__((unused))) {
     char path[PATH_MAX];
@@ -887,9 +903,9 @@
     MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
            dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
 
-    int fd = TEMP_FAILURE_RETRY(
-        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+    if (fd.get() < 0) {
         printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
     } else {
         if (add_to_zip) {
@@ -901,7 +917,7 @@
         } else {
             MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
                    anr_traces_file.c_str());
-            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd);
+            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
         }
     }
 }
@@ -934,12 +950,12 @@
         AddDumps(anr_data->begin(), anr_data->begin() + 1,
                  "VM TRACES AT LAST ANR", add_to_zip);
 
-        if (anr_data->size() > 1) {
-            // NOTE: Historical ANRs are always added as separate entries in the
-            // bugreport zip file.
-            AddDumps(anr_data->begin() + 1, anr_data->end(),
-                     "HISTORICAL ANR", true /* add_to_zip */);
-        }
+        // The "last" ANR will always be included as separate entry in the zip file. In addition,
+        // it will be present in the body of the main entry if |add_to_zip| == false.
+        //
+        // Historical ANRs are always included as separate entries in the bugreport zip file.
+        AddDumps(anr_data->begin() + ((add_to_zip) ? 1 : 0), anr_data->end(),
+                 "HISTORICAL ANR", true /* add_to_zip */);
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
     }
@@ -2034,5 +2050,8 @@
         close(ds.control_socket_fd_);
     }
 
+    CloseDumpFds(tombstone_data.get());
+    CloseDumpFds(anr_data.get());
+
     return 0;
 }
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index c2c9071..6ff0dae 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -632,7 +632,7 @@
     struct dirent *d;
     char *newpath = NULL;
     const char *slash = "/";
-    int fd, retval = 0;
+    int retval = 0;
 
     if (!title.empty()) {
         printf("------ %s (%s) ------\n", title.c_str(), dir);
@@ -674,13 +674,13 @@
             }
             continue;
         }
-        fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-        if (fd < 0) {
-            retval = fd;
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+        if (fd.get() < 0) {
+            retval = -1;
             printf("*** %s: %s\n", newpath, strerror(errno));
             continue;
         }
-        (*dump_from_fd)(NULL, newpath, fd);
+        (*dump_from_fd)(NULL, newpath, fd.get());
     }
     closedir(dirp);
     if (!title.empty()) {
@@ -699,11 +699,9 @@
     int flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
         printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
-        close(fd);
         return -1;
     } else if (!(flags & O_NONBLOCK)) {
         printf("*** %s: fd must have O_NONBLOCK set.\n", path);
-        close(fd);
         return -1;
     }
     return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index bfc6f28..b5295f2 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -136,5 +136,101 @@
     return NO_ERROR;
 }
 
+void DisplayState::merge(const DisplayState& other) {
+    if (other.what & eSurfaceChanged) {
+        what |= eSurfaceChanged;
+        surface = other.surface;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eDisplayProjectionChanged) {
+        what |= eDisplayProjectionChanged;
+        orientation = other.orientation;
+        viewport = other.viewport;
+        frame = other.frame;
+    }
+    if (other.what & eDisplaySizeChanged) {
+        what |= eDisplaySizeChanged;
+        width = other.width;
+        height = other.height;
+    }
+}
+
+void layer_state_t::merge(const layer_state_t& other) {
+    if (other.what & ePositionChanged) {
+        what |= ePositionChanged;
+        x = other.x;
+        y = other.y;
+    }
+    if (other.what & eLayerChanged) {
+        what |= eLayerChanged;
+        z = other.z;
+    }
+    if (other.what & eSizeChanged) {
+        what |= eSizeChanged;
+        w = other.w;
+        h = other.h;
+    }
+    if (other.what & eAlphaChanged) {
+        what |= eAlphaChanged;
+        alpha = other.alpha;
+    }
+    if (other.what & eMatrixChanged) {
+        what |= eMatrixChanged;
+        matrix = other.matrix;
+    }
+    if (other.what & eTransparentRegionChanged) {
+        what |= eTransparentRegionChanged;
+        transparentRegion = other.transparentRegion;
+    }
+    if (other.what & eFlagsChanged) {
+        what |= eFlagsChanged;
+        flags = other.flags;
+        mask = other.mask;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eDeferTransaction) {
+        what |= eDeferTransaction;
+        barrierHandle = other.barrierHandle;
+        barrierGbp = other.barrierGbp;
+        frameNumber = other.frameNumber;
+    }
+    if (other.what & eFinalCropChanged) {
+        what |= eFinalCropChanged;
+        finalCrop = other.finalCrop;
+    }
+    if (other.what & eOverrideScalingModeChanged) {
+        what |= eOverrideScalingModeChanged;
+        overrideScalingMode = other.overrideScalingMode;
+    }
+    if (other.what & eGeometryAppliesWithResize) {
+        what |= eGeometryAppliesWithResize;
+    }
+    if (other.what & eReparentChildren) {
+        what |= eReparentChildren;
+        reparentHandle = other.reparentHandle;
+    }
+    if (other.what & eDetachChildren) {
+        what |= eDetachChildren;
+    }
+    if (other.what & eRelativeLayerChanged) {
+        what |= eRelativeLayerChanged;
+        z = other.z;
+        relativeLayerHandle = other.relativeLayerHandle;
+    }
+    if (other.what & eReparent) {
+        what |= eReparent;
+        parentHandleForChild = other.parentHandleForChild;
+    }
+}
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 15c4c9a..2adc273 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -104,6 +104,30 @@
     mComposerStates = other.mComposerStates;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+    for (auto const& state : other.mComposerStates) {
+        ssize_t index = mComposerStates.indexOf(state);
+        if (index < 0) {
+            mComposerStates.add(state);
+        } else {
+            mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state);
+        }
+    }
+    other.mComposerStates.clear();
+
+    for (auto const& state : other.mDisplayStates) {
+        ssize_t index = mDisplayStates.indexOf(state);
+        if (index < 0) {
+            mDisplayStates.add(state);
+        } else {
+            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+        }
+    }
+    other.mDisplayStates.clear();
+
+    return *this;
+}
+
 status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
     if (mStatus != NO_ERROR) {
         return mStatus;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ae6965a..f3fb82f 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -77,6 +77,7 @@
         matrix.dsdy = matrix.dtdx = 0.0f;
     }
 
+    void merge(const layer_state_t& other);
     status_t    write(Parcel& output) const;
     status_t    read(const Parcel& input);
 
@@ -144,6 +145,7 @@
     };
 
     DisplayState();
+    void merge(const DisplayState& other);
 
     uint32_t what;
     sp<IBinder> token;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d63dafe..87fdfae 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -144,7 +144,9 @@
         Transaction(Transaction const& other);
 
         status_t apply(bool synchronous = false);
-
+        // Merge another transaction in to this one, clearing other
+        // as if it had been applied.
+        Transaction& merge(Transaction&& other);
         Transaction& show(const sp<SurfaceControl>& sc);
         Transaction& hide(const sp<SurfaceControl>& sc);
         Transaction& setPosition(const sp<SurfaceControl>& sc,
@@ -175,8 +177,6 @@
                 float alpha);
         Transaction& setMatrix(const sp<SurfaceControl>& sc,
                 float dsdx, float dtdx, float dtdy, float dsdy);
-        Transaction& setOrientation(const sp<SurfaceControl>& sc,
-                const Rect& crop);
         Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index c4ffb41..5e4df84 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -54,7 +54,7 @@
     tags: ["optional"],
 }
 
-cc_test {
+cc_benchmark {
     srcs: ["buffer_transport_benchmark.cpp"],
     static_libs: static_libraries,
     shared_libs: shared_libraries,
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
index 5b580df..658b496 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
@@ -1,24 +1,24 @@
 #include <android/native_window.h>
-#include <base/logging.h>
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <dvr/dvr_api.h>
 #include <dvr/performance_client_api.h>
-#include <gtest/gtest.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 #include <private/dvr/buffer_hub_queue_producer.h>
 #include <utils/Trace.h>
 
+#include <chrono>
 #include <functional>
-#include <mutex>
+#include <iostream>
 #include <thread>
 #include <vector>
 
 #include <poll.h>
 #include <sys/wait.h>
-#include <unistd.h>  // for pipe
 
 // Use ALWAYS at the tag level. Control is performed manually during command
 // line processing.
@@ -29,6 +29,7 @@
 
 using namespace android;
 using namespace android::dvr;
+using ::benchmark::State;
 
 static const String16 kBinderService = String16("bufferTransport");
 static const uint32_t kBufferWidth = 100;
@@ -38,82 +39,13 @@
 static const uint64_t kBufferUsage =
     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
 static const int kMaxAcquiredImages = 1;
+static const int kQueueDepth = 2;  // We are double buffering for this test.
 static const size_t kMaxQueueCounts = 128;
 
-static int gConcurrency = 1;  // 1 writer at a time
-static int gIterations = 1000;  // 1K times
-static int gSleepIntervalUs = 16 * 1000;  // 16ms
-
 enum BufferTransportServiceCode {
   CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
 };
 
-// A mininal cross process helper class based on a bidirectional pipe pair. This
-// is used to signal that Binder-based BufferTransportService has finished
-// initialization.
-class Pipe {
- public:
-  static std::tuple<Pipe, Pipe> CreatePipePair() {
-    int a[2] = {-1, -1};
-    int b[2] = {-1, -1};
-
-    pipe(a);
-    pipe(b);
-
-    return std::make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
-  }
-
-  Pipe() = default;
-
-  Pipe(Pipe&& other) {
-    read_fd_ = other.read_fd_;
-    write_fd_ = other.write_fd_;
-    other.read_fd_ = 0;
-    other.write_fd_ = 0;
-  }
-
-  Pipe& operator=(Pipe&& other) {
-    Reset();
-    read_fd_ = other.read_fd_;
-    write_fd_ = other.write_fd_;
-    other.read_fd_ = 0;
-    other.write_fd_ = 0;
-    return *this;
-  }
-
-  ~Pipe() { Reset(); }
-
-  Pipe(const Pipe&) = delete;
-  Pipe& operator=(const Pipe&) = delete;
-  Pipe& operator=(const Pipe&&) = delete;
-
-  bool IsValid() { return read_fd_ > 0 && write_fd_ > 0; }
-
-  void Signal() {
-    bool val = true;
-    int error = write(write_fd_, &val, sizeof(val));
-    ASSERT_GE(error, 0);
-  };
-
-  void Wait() {
-    bool val = false;
-    int error = read(read_fd_, &val, sizeof(val));
-    ASSERT_GE(error, 0);
-  }
-
-  void Reset() {
-    if (read_fd_)
-      close(read_fd_);
-    if (write_fd_)
-      close(write_fd_);
-  }
-
- private:
-  int read_fd_ = -1;
-  int write_fd_ = -1;
-  Pipe(int read_fd, int write_fd) : read_fd_{read_fd}, write_fd_{write_fd} {}
-};
-
 // A binder services that minics a compositor that consumes buffers. It provides
 // one Binder interface to create a new Surface for buffer producer to write
 // into; while itself will carry out no-op buffer consuming by acquiring then
@@ -149,8 +81,6 @@
           buffer_item_consumer_(buffer_item_consumer) {}
 
     void onFrameAvailable(const BufferItem& /*item*/) override {
-      std::unique_lock<std::mutex> autolock(service_->reader_mutex_);
-
       BufferItem buffer;
       status_t ret = 0;
       {
@@ -197,7 +127,6 @@
     sp<FrameListener> frame_listener_;
   };
 
-  std::mutex reader_mutex_;
   std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
 };
 
@@ -225,32 +154,19 @@
  public:
   BinderBufferTransport() {}
 
-  ~BinderBufferTransport() {
-    if (client_pipe_.IsValid()) {
-      client_pipe_.Signal();
-      LOG(INFO) << "Client signals service to shut down.";
-    }
-  }
-
   int Start() override {
-    // Fork a process to run a binder server. The parent process will return
-    // a pipe here, and we use the pipe to signal the binder server to exit.
-    client_pipe_ = CreateBinderServer();
+    sp<IServiceManager> sm = defaultServiceManager();
+    service_ = sm->getService(kBinderService);
+    if (service_ == nullptr) {
+      LOG(ERROR) << "Failed to get the benchmark service.";
+      return -EIO;
+    }
 
-    // Wait until service is ready.
-    LOG(INFO) << "Service is ready for client.";
-    client_pipe_.Wait();
+    LOG(INFO) << "Binder server is ready for client.";
     return 0;
   }
 
   sp<Surface> CreateSurface() override {
-    sp<IServiceManager> sm = defaultServiceManager();
-    service_ = sm->getService(kBinderService);
-    if (service_ == nullptr) {
-      LOG(ERROR) << "Failed to set the benchmark service.";
-      return nullptr;
-    }
-
     Parcel data;
     Parcel reply;
     int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
@@ -283,38 +199,7 @@
   }
 
  private:
-  static Pipe CreateBinderServer() {
-    std::tuple<Pipe, Pipe> pipe_pair = Pipe::CreatePipePair();
-    pid_t pid = fork();
-    if (pid) {
-      // parent, i.e. the client side.
-      ProcessState::self()->startThreadPool();
-      LOG(INFO) << "Binder server pid: " << pid;
-      return std::move(std::get<0>(pipe_pair));
-    } else {
-      // child, i.e. the service side.
-      Pipe service_pipe = std::move(std::get<1>(pipe_pair));
-
-      ProcessState::self()->startThreadPool();
-      sp<IServiceManager> sm = defaultServiceManager();
-      sp<BufferTransportService> service = new BufferTransportService;
-      sm->addService(kBinderService, service, false);
-
-      LOG(INFO) << "Binder Service Running...";
-
-      service_pipe.Signal();
-      service_pipe.Wait();
-
-      LOG(INFO) << "Service Exiting...";
-      exit(EXIT_SUCCESS);
-
-      /* never get here */
-      return {};
-    }
-  }
-
   sp<IBinder> service_;
-  Pipe client_pipe_;
 };
 
 // BufferHub/PDX-based buffer transport.
@@ -378,7 +263,6 @@
         const int num_events = ret;
         for (int i = 0; i < num_events; i++) {
           uint32_t surface_index = events[i].data.u32;
-          // LOG(INFO) << "!!! handle queue events index: " << surface_index;
           buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents();
         }
       }
@@ -390,8 +274,6 @@
   }
 
   sp<Surface> CreateSurface() override {
-    std::lock_guard<std::mutex> autolock(queue_mutex_);
-
     auto new_queue = std::make_shared<BufferQueueHolder>();
     if (new_queue->producer_ == nullptr) {
       LOG(ERROR) << "Failed to create buffer producer.";
@@ -472,8 +354,6 @@
   std::atomic<bool> stopped_;
   std::thread reader_thread_;
 
-  // Mutex to guard epoll_fd_ and buffer_queues_.
-  std::mutex queue_mutex_;
   EpollFileDescriptor epoll_fd_;
   std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
 };
@@ -486,124 +366,155 @@
 // Main test suite, which supports two transport backend: 1) BinderBufferQueue,
 // 2) BufferHubQueue. The test case drives the producer end of both transport
 // backend by queuing buffers into the buffer queue by using ANativeWindow API.
-class BufferTransportBenchmark
-    : public ::testing::TestWithParam<TransportType> {
+class BufferTransportBenchmark : public ::benchmark::Fixture {
  public:
-  void SetUp() override {
-    switch (GetParam()) {
-      case kBinderBufferTransport:
-        transport_.reset(new BinderBufferTransport);
-        break;
-      case kBufferHubTransport:
-        transport_.reset(new BufferHubTransport);
-        break;
-      default:
-        FAIL() << "Unknown test case.";
-        break;
+  void SetUp(State& state) override {
+    if (state.thread_index == 0) {
+      const int transport = state.range(0);
+      switch (transport) {
+        case kBinderBufferTransport:
+          transport_.reset(new BinderBufferTransport);
+          break;
+        case kBufferHubTransport:
+          transport_.reset(new BufferHubTransport);
+          break;
+        default:
+          CHECK(false) << "Unknown test case.";
+          break;
+      }
+
+      CHECK(transport_);
+      const int ret = transport_->Start();
+      CHECK_EQ(ret, 0);
+
+      LOG(INFO) << "Transport backend running, transport=" << transport << ".";
+
+      // Create surfaces for each thread.
+      surfaces_.resize(state.threads);
+      for (int i = 0; i < state.threads; i++) {
+        // Common setup every thread needs.
+        surfaces_[i] = transport_->CreateSurface();
+        CHECK(surfaces_[i]);
+
+        LOG(INFO) << "Surface initialized on thread " << i << ".";
+      }
+    }
+  }
+
+  void TearDown(State& state) override {
+    if (state.thread_index == 0) {
+      surfaces_.clear();
+      transport_.reset();
+      LOG(INFO) << "Tear down benchmark.";
     }
   }
 
  protected:
-  void ProduceBuffers(sp<Surface> surface, int iterations, int sleep_usec) {
-    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_Buffer buffer;
-    int32_t error = 0;
+  std::unique_ptr<BufferTransport> transport_;
+  std::vector<sp<Surface>> surfaces_;
+};
 
-    for (int i = 0; i < iterations; i++) {
-      usleep(sleep_usec);
+BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
+  ANativeWindow* window = nullptr;
+  ANativeWindow_Buffer buffer;
+  int32_t error = 0;
+  double total_gain_buffer_us = 0;
+  double total_post_buffer_us = 0;
+  int iterations = 0;
 
-      {
-        ATRACE_NAME("GainBuffer");
+  while (state.KeepRunning()) {
+    if (window == nullptr) {
+      CHECK(surfaces_[state.thread_index]);
+      window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
+
+      // Lock buffers a couple time from the queue, so that we have the buffer
+      // allocated.
+      for (int i = 0; i < kQueueDepth; i++) {
         error = ANativeWindow_lock(window, &buffer,
                                    /*inOutDirtyBounds=*/nullptr);
-      }
-      ASSERT_EQ(error, 0);
-
-      {
-        ATRACE_NAME("PostBuffer");
+        CHECK_EQ(error, 0);
         error = ANativeWindow_unlockAndPost(window);
+        CHECK_EQ(error, 0);
       }
-      ASSERT_EQ(error, 0);
+    }
+
+    {
+      ATRACE_NAME("GainBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_lock(window, &buffer,
+                                 /*inOutDirtyBounds=*/nullptr);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_gain_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    {
+      ATRACE_NAME("PostBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_unlockAndPost(window);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_post_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    iterations++;
+  }
+
+  state.counters["gain_buffer_us"] = ::benchmark::Counter(
+      total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["post_buffer_us"] = ::benchmark::Counter(
+      total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["producer_us"] = ::benchmark::Counter(
+      (total_gain_buffer_us + total_post_buffer_us) / iterations,
+      ::benchmark::Counter::kAvgThreads);
+}
+
+BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
+    ->Unit(::benchmark::kMicrosecond)
+    ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
+    ->ThreadRange(1, 32);
+
+static void runBinderServer() {
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  ProcessState::self()->startThreadPool();
+
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<BufferTransportService> service = new BufferTransportService;
+  sm->addService(kBinderService, service, false);
+
+  LOG(INFO) << "Binder server running...";
+
+  while (true) {
+    int stat, retval;
+    retval = wait(&stat);
+    if (retval == -1 && errno == ECHILD) {
+      break;
     }
   }
 
-  std::unique_ptr<BufferTransport> transport_;
-};
-
-TEST_P(BufferTransportBenchmark, ContinuousLoad) {
-  ASSERT_NE(transport_, nullptr);
-  const int ret = transport_->Start();
-  ASSERT_EQ(ret, 0);
-
-  LOG(INFO) << "Start Running.";
-
-  std::vector<std::thread> writer_threads;
-  for (int i = 0; i < gConcurrency; i++) {
-    std::thread writer_thread = std::thread([this]() {
-      sp<Surface> surface = transport_->CreateSurface();
-      ASSERT_NE(surface, nullptr);
-
-      ASSERT_NO_FATAL_FAILURE(
-          ProduceBuffers(surface, gIterations, gSleepIntervalUs));
-
-      usleep(1000 * 100);
-    });
-
-    writer_threads.push_back(std::move(writer_thread));
-  }
-
-  for (auto& writer_thread : writer_threads) {
-    writer_thread.join();
-  }
-
-  LOG(INFO) << "All done.";
-};
-
-INSTANTIATE_TEST_CASE_P(BufferTransportBenchmarkInstance,
-                        BufferTransportBenchmark,
-                        ::testing::ValuesIn({kBinderBufferTransport,
-                                             kBufferHubTransport}));
+  LOG(INFO) << "Service Exiting...";
+}
 
 // To run binder-based benchmark, use:
 // adb shell buffer_transport_benchmark \
-//   --gtest_filter="BufferTransportBenchmark.ContinuousLoad/0"
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
 //
 // To run bufferhub-based benchmark, use:
 // adb shell buffer_transport_benchmark \
-//   --gtest_filter="BufferTransportBenchmark.ContinuousLoad/1"
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
 int main(int argc, char** argv) {
   bool tracing_enabled = false;
 
-  // Parse arguments in addition to "--gtest_filter" paramters.
+  // Parse arguments in addition to "--benchmark_filter" paramters.
   for (int i = 1; i < argc; i++) {
     if (std::string(argv[i]) == "--help") {
       std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
-      std::cout << "\t-c N: Specify number of concurrent writer threads, "
-                   "(default: 1, max: 128)."
-                << std::endl;
-      std::cout << "\t-i N: Specify number of iterations, (default: 1000)."
-                << std::endl;
-      std::cout << "\t-s N: Specify sleep interval in usec, (default: 16000)."
-                << std::endl;
       std::cout << "\t--trace: Enable systrace logging."
                 << std::endl;
       return 0;
     }
-    if (std::string(argv[i]) == "-c") {
-      gConcurrency = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
-    if (std::string(argv[i]) == "-s") {
-      gSleepIntervalUs = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
-    if (std::string(argv[i]) == "-i") {
-      gIterations = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
     if (std::string(argv[i]) == "--trace") {
       tracing_enabled = true;
       continue;
@@ -614,6 +525,15 @@
   atrace_setup();
   atrace_set_tracing_enabled(tracing_enabled);
 
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  pid_t pid = fork();
+  if (pid == 0) {
+    // parent, i.e. the client side.
+    ProcessState::self()->startThreadPool();
+
+    ::benchmark::Initialize(&argc, argv);
+    ::benchmark::RunSpecifiedBenchmarks();
+  } else {
+    LOG(INFO) << "Benchmark process pid: " << pid;
+    runBinderServer();
+  }
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ec87eee..16a16a5 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -891,6 +891,30 @@
     }
 }
 
+TEST_F(LayerUpdateTest, MergingTransactions) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before move");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(0, 12);
+        sc->expectFGColor(75, 75);
+        sc->expectBGColor(145, 145);
+    }
+
+    Transaction t1, t2;
+    t1.setPosition(mFGSurfaceControl, 128, 128);
+    t2.setPosition(mFGSurfaceControl, 0, 0);
+    // We expect that the position update from t2 now
+    // overwrites the position update from t1.
+    t1.merge(std::move(t2));
+    t1.apply();
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectFGColor(1, 1);
+    }
+}
+
 class ChildLayerTest : public LayerUpdateTest {
 protected:
     void SetUp() override {