Merge "Simplify PERFETTO_EXPORT_COMPONENT"
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index a4c7777..51deba3 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -319,6 +319,7 @@
     "../../base",
     "../../base:test_support",
     "../../tracing/core",
+    "../../tracing/test:test_support",
     "../common:proc_utils",
     "../common:unwind_support",
   ]
diff --git a/src/profiling/memory/heapprofd_producer_unittest.cc b/src/profiling/memory/heapprofd_producer_unittest.cc
index 78ed9ea..44dd606 100644
--- a/src/profiling/memory/heapprofd_producer_unittest.cc
+++ b/src/profiling/memory/heapprofd_producer_unittest.cc
@@ -22,6 +22,7 @@
 #include "perfetto/ext/tracing/core/commit_data_request.h"
 #include "perfetto/tracing/core/data_source_descriptor.h"
 #include "src/base/test/test_task_runner.h"
+#include "src/tracing/test/mock_producer_endpoint.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
@@ -32,29 +33,6 @@
 using ::testing::Pair;
 using ::testing::Property;
 
-class MockProducerEndpoint : public TracingService::ProducerEndpoint {
- public:
-  MOCK_METHOD1(UnregisterDataSource, void(const std::string&));
-  MOCK_METHOD1(NotifyFlushComplete, void(FlushRequestID));
-  MOCK_METHOD1(NotifyDataSourceStarted, void(DataSourceInstanceID));
-  MOCK_METHOD1(NotifyDataSourceStopped, void(DataSourceInstanceID));
-
-  MOCK_CONST_METHOD0(shared_memory, SharedMemory*());
-  MOCK_CONST_METHOD0(shared_buffer_page_size_kb, size_t());
-  MOCK_METHOD2(CreateTraceWriter,
-               std::unique_ptr<TraceWriter>(BufferID, BufferExhaustedPolicy));
-  MOCK_METHOD0(MaybeSharedMemoryArbiter, SharedMemoryArbiter*());
-  MOCK_CONST_METHOD0(IsShmemProvidedByProducer, bool());
-  MOCK_METHOD1(ActivateTriggers, void(const std::vector<std::string>&));
-
-  MOCK_METHOD1(RegisterDataSource, void(const DataSourceDescriptor&));
-  MOCK_METHOD1(UpdateDataSource, void(const DataSourceDescriptor&));
-  MOCK_METHOD2(CommitData, void(const CommitDataRequest&, CommitDataCallback));
-  MOCK_METHOD2(RegisterTraceWriter, void(uint32_t, uint32_t));
-  MOCK_METHOD1(UnregisterTraceWriter, void(uint32_t));
-  MOCK_METHOD1(Sync, void(std::function<void()>));
-};
-
 TEST(LogHistogramTest, Simple) {
   LogHistogram h;
   h.Add(1);
diff --git a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
index 140a881..0d5e9c7 100644
--- a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
@@ -27,7 +27,7 @@
 #include "src/base/test/test_task_runner.h"
 #include "src/tracing/core/patch_list.h"
 #include "src/tracing/test/aligned_buffer_test.h"
-#include "src/tracing/test/fake_producer_endpoint.h"
+#include "src/tracing/test/mock_producer_endpoint.h"
 #include "test/gtest_and_gmock.h"
 
 #include "protos/perfetto/trace/test_event.pbzero.h"
@@ -38,31 +38,8 @@
 using testing::_;
 using testing::Invoke;
 using testing::Mock;
-
-class MockProducerEndpoint : public TracingService::ProducerEndpoint {
- public:
-  void RegisterDataSource(const DataSourceDescriptor&) override {}
-  void UpdateDataSource(const DataSourceDescriptor&) override {}
-  void UnregisterDataSource(const std::string&) override {}
-  void NotifyFlushComplete(FlushRequestID) override {}
-  void NotifyDataSourceStarted(DataSourceInstanceID) override {}
-  void NotifyDataSourceStopped(DataSourceInstanceID) override {}
-  void ActivateTriggers(const std::vector<std::string>&) {}
-  void Sync(std::function<void()>) override {}
-  SharedMemory* shared_memory() const override { return nullptr; }
-  size_t shared_buffer_page_size_kb() const override { return 0; }
-  std::unique_ptr<TraceWriter> CreateTraceWriter(
-      BufferID,
-      BufferExhaustedPolicy) override {
-    return nullptr;
-  }
-  SharedMemoryArbiter* MaybeSharedMemoryArbiter() override { return nullptr; }
-  bool IsShmemProvidedByProducer() const override { return false; }
-
-  MOCK_METHOD2(CommitData, void(const CommitDataRequest&, CommitDataCallback));
-  MOCK_METHOD2(RegisterTraceWriter, void(uint32_t, uint32_t));
-  MOCK_METHOD1(UnregisterTraceWriter, void(uint32_t));
-};
+using testing::NiceMock;
+using testing::UnorderedElementsAreArray;
 
 class SharedMemoryArbiterImplTest : public AlignedBufferTest {
  public:
@@ -83,7 +60,7 @@
 
   std::unique_ptr<base::TestTaskRunner> task_runner_;
   std::unique_ptr<SharedMemoryArbiterImpl> arbiter_;
-  MockProducerEndpoint mock_producer_endpoint_;
+  NiceMock<MockProducerEndpoint> mock_producer_endpoint_;
   std::function<void(const std::vector<uint32_t>&)> on_pages_complete_;
 };
 
@@ -225,49 +202,23 @@
   arbiter_->FlushPendingCommitDataRequests();
 }
 
-// Helper for verifying trace writer id allocations.
-class TraceWriterIdChecker : public FakeProducerEndpoint {
- public:
-  TraceWriterIdChecker(std::function<void()> checkpoint)
-      : checkpoint_(std::move(checkpoint)) {}
-
-  void RegisterTraceWriter(uint32_t id, uint32_t) override {
-    EXPECT_GT(id, 0u);
-    EXPECT_LE(id, kMaxWriterID);
-    if (id > 0 && id <= kMaxWriterID) {
-      registered_ids_.set(id - 1);
-    }
-  }
-
-  void UnregisterTraceWriter(uint32_t id) override {
-    if (++unregister_calls_ == kMaxWriterID)
-      checkpoint_();
-
-    EXPECT_GT(id, 0u);
-    EXPECT_LE(id, kMaxWriterID);
-    if (id > 0 && id <= kMaxWriterID) {
-      unregistered_ids_.set(id - 1);
-    }
-  }
-
-  // bit N corresponds to id N+1
-  std::bitset<kMaxWriterID> registered_ids_;
-  std::bitset<kMaxWriterID> unregistered_ids_;
-
-  int unregister_calls_ = 0;
-
- private:
-  std::function<void()> checkpoint_;
-};
-
 // Check that we can actually create up to kMaxWriterID TraceWriter(s).
 TEST_P(SharedMemoryArbiterImplTest, WriterIDsAllocation) {
   auto checkpoint = task_runner_->CreateCheckpoint("last_unregistered");
 
-  TraceWriterIdChecker id_checking_endpoint(checkpoint);
-  arbiter_.reset(new SharedMemoryArbiterImpl(buf(), buf_size(), page_size(),
-                                             &id_checking_endpoint,
-                                             task_runner_.get()));
+  std::vector<uint32_t> registered_ids;
+  std::vector<uint32_t> unregistered_ids;
+
+  ON_CALL(mock_producer_endpoint_, RegisterTraceWriter)
+      .WillByDefault(
+          [&](uint32_t id, uint32_t) { registered_ids.push_back(id); });
+  ON_CALL(mock_producer_endpoint_, UnregisterTraceWriter)
+      .WillByDefault([&](uint32_t id) {
+        unregistered_ids.push_back(id);
+        if (unregistered_ids.size() == kMaxWriterID) {
+          checkpoint();
+        }
+      });
   {
     std::map<WriterID, std::unique_ptr<TraceWriter>> writers;
 
@@ -287,8 +238,11 @@
   // memory arbiter.
   task_runner_->RunUntilCheckpoint("last_unregistered", 15000);
 
-  EXPECT_TRUE(id_checking_endpoint.registered_ids_.all());
-  EXPECT_TRUE(id_checking_endpoint.unregistered_ids_.all());
+  std::vector<uint32_t> expected_ids;  // 1..kMaxWriterID
+  for (uint32_t i = 1; i <= kMaxWriterID; i++)
+    expected_ids.push_back(i);
+  EXPECT_THAT(registered_ids, UnorderedElementsAreArray(expected_ids));
+  EXPECT_THAT(unregistered_ids, UnorderedElementsAreArray(expected_ids));
 }
 
 TEST_P(SharedMemoryArbiterImplTest, Shutdown) {
diff --git a/src/tracing/core/trace_writer_impl_unittest.cc b/src/tracing/core/trace_writer_impl_unittest.cc
index a0f3f3d..6750880 100644
--- a/src/tracing/core/trace_writer_impl_unittest.cc
+++ b/src/tracing/core/trace_writer_impl_unittest.cc
@@ -16,40 +16,66 @@
 
 #include "src/tracing/core/trace_writer_impl.h"
 
+#include <vector>
+
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/tracing/core/commit_data_request.h"
+#include "perfetto/ext/tracing/core/shared_memory_abi.h"
 #include "perfetto/ext/tracing/core/trace_writer.h"
 #include "perfetto/ext/tracing/core/tracing_service.h"
+#include "perfetto/protozero/proto_utils.h"
 #include "src/base/test/gtest_test_suite.h"
 #include "src/base/test/test_task_runner.h"
 #include "src/tracing/core/shared_memory_arbiter_impl.h"
 #include "src/tracing/test/aligned_buffer_test.h"
-#include "src/tracing/test/fake_producer_endpoint.h"
+#include "src/tracing/test/mock_producer_endpoint.h"
 #include "test/gtest_and_gmock.h"
 
+#include "protos/perfetto/trace/test_event.gen.h"
 #include "protos/perfetto/trace/test_event.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 
 namespace perfetto {
 namespace {
 
+using ChunkHeader = SharedMemoryABI::ChunkHeader;
 using ::testing::AllOf;
 using ::testing::MockFunction;
 using ::testing::Ne;
+using ::testing::NiceMock;
 using ::testing::NotNull;
 using ::testing::SizeIs;
 using ::testing::ValuesIn;
 
 class TraceWriterImplTest : public AlignedBufferTest {
  public:
+  struct PatchKey {
+    uint32_t writer_id;
+    uint32_t chunk_id;
+    bool operator<(const PatchKey& other) const {
+      return std::tie(writer_id, chunk_id) <
+             std::tie(other.writer_id, other.chunk_id);
+    }
+  };
   void SetUp() override {
     SharedMemoryArbiterImpl::set_default_layout_for_testing(
         SharedMemoryABI::PageLayout::kPageDiv4);
     AlignedBufferTest::SetUp();
     task_runner_.reset(new base::TestTaskRunner());
     arbiter_.reset(new SharedMemoryArbiterImpl(buf(), buf_size(), page_size(),
-                                               &fake_producer_endpoint_,
+                                               &mock_producer_endpoint_,
                                                task_runner_.get()));
+    ON_CALL(mock_producer_endpoint_, CommitData)
+        .WillByDefault([&](const CommitDataRequest& req,
+                           MockProducerEndpoint::CommitDataCallback cb) {
+          last_commit_ = req;
+          last_commit_callback_ = cb;
+          for (const CommitDataRequest::ChunkToPatch& c :
+               req.chunks_to_patch()) {
+            patches_[PatchKey{c.writer_id(), c.chunk_id()}] = c.patches();
+          }
+        });
   }
 
   void TearDown() override {
@@ -57,7 +83,99 @@
     task_runner_.reset();
   }
 
-  FakeProducerEndpoint fake_producer_endpoint_;
+  std::vector<uint8_t> CopyPayloadAndApplyPatches(
+      SharedMemoryABI::Chunk& chunk) const {
+    std::vector<uint8_t> copy(chunk.payload_begin(),
+                              chunk.payload_begin() + chunk.payload_size());
+    ChunkHeader::Packets p = chunk.header()->packets.load();
+
+    auto it = patches_.find(PatchKey{chunk.header()->writer_id.load(),
+                                     chunk.header()->chunk_id.load()});
+    if (it == patches_.end()) {
+      EXPECT_FALSE(p.flags & ChunkHeader::kChunkNeedsPatching);
+      return copy;
+    }
+    EXPECT_TRUE(p.flags & ChunkHeader::kChunkNeedsPatching);
+
+    for (const CommitDataRequest::ChunkToPatch::Patch& patch : it->second) {
+      if (patch.offset() + patch.data().size() > copy.size()) {
+        ADD_FAILURE() << "Patch out of bounds";
+        continue;
+      }
+      for (size_t i = 0; i < patch.data().size(); i++) {
+        copy[patch.offset() + i] =
+            reinterpret_cast<const uint8_t*>(patch.data().data())[i];
+      }
+    }
+    return copy;
+  }
+
+  // Extracts trace packets from the shared memory buffer, and returns copies of
+  // them (after applying the patches received). The producer that writes to the
+  // shared memory (i.e. the trace writer) must be destroyed.
+  std::vector<std::string> GetPacketsFromShmemAndPatches() {
+    std::vector<std::string> packets;
+    SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
+    bool was_fragmenting = false;
+    for (size_t page_idx = 0; page_idx < abi->num_pages(); page_idx++) {
+      uint32_t page_layout = abi->GetPageLayout(page_idx);
+      size_t num_chunks = SharedMemoryABI::GetNumChunksForLayout(page_layout);
+      for (size_t chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++) {
+        SharedMemoryABI::ChunkState chunk_state =
+            abi->GetChunkState(page_idx, chunk_idx);
+        if (chunk_state != SharedMemoryABI::kChunkFree &&
+            chunk_state != SharedMemoryABI::kChunkComplete) {
+          ADD_FAILURE() << "Page " << page_idx << " chunk " << chunk_idx
+                        << " unexpected state: " << chunk_state;
+          continue;
+        }
+        SharedMemoryABI::Chunk chunk =
+            abi->TryAcquireChunkForReading(page_idx, chunk_idx);
+        if (!chunk.is_valid())
+          continue;
+        ChunkHeader::Packets p = chunk.header()->packets.load();
+
+        EXPECT_EQ(
+            was_fragmenting,
+            static_cast<bool>(p.flags &
+                              ChunkHeader::kFirstPacketContinuesFromPrevChunk));
+
+        std::vector<uint8_t> payload = CopyPayloadAndApplyPatches(chunk);
+
+        const uint8_t* read_ptr = payload.data();
+        const uint8_t* const end_read_ptr = payload.data() + payload.size();
+
+        size_t num_fragments = p.count;
+        for (; num_fragments && read_ptr < end_read_ptr; num_fragments--) {
+          uint64_t len;
+          read_ptr =
+              protozero::proto_utils::ParseVarInt(read_ptr, end_read_ptr, &len);
+          if (!was_fragmenting || packets.empty()) {
+            packets.push_back(std::string());
+          }
+          if (read_ptr + len > end_read_ptr) {
+            ADD_FAILURE() << "Page " << page_idx << " chunk " << chunk_idx
+                          << " malformed chunk";
+          }
+          packets.back().append(reinterpret_cast<const char*>(read_ptr),
+                                static_cast<size_t>(len));
+          read_ptr += len;
+        }
+        EXPECT_EQ(num_fragments, 0u);
+        if (p.flags & ChunkHeader::kLastPacketContinuesOnNextChunk) {
+          was_fragmenting = true;
+        }
+      }
+    }
+    return packets;
+  }
+
+  CommitDataRequest last_commit_;
+  ProducerEndpoint::CommitDataCallback last_commit_callback_;
+  std::map<PatchKey, std::vector<CommitDataRequest::ChunkToPatch::Patch>>
+      patches_;
+  NiceMock<MockProducerEndpoint> mock_producer_endpoint_;
+
   std::unique_ptr<base::TestTaskRunner> task_runner_;
   std::unique_ptr<SharedMemoryArbiterImpl> arbiter_;
 };
@@ -65,7 +183,7 @@
 size_t const kPageSizes[] = {4096, 65536};
 INSTANTIATE_TEST_SUITE_P(PageSize, TraceWriterImplTest, ValuesIn(kPageSizes));
 
-TEST_P(TraceWriterImplTest, SingleWriter) {
+TEST_P(TraceWriterImplTest, NewTracePacket) {
   const BufferID kBufId = 42;
   std::unique_ptr<TraceWriter> writer = arbiter_->CreateTraceWriter(kBufId);
   const size_t kNumPackets = 32;
@@ -79,31 +197,21 @@
   // and the chunk to be put back in the kChunkComplete state.
   writer.reset();
 
-  SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
-  size_t packets_count = 0;
-  for (size_t page_idx = 0; page_idx < abi->num_pages(); page_idx++) {
-    uint32_t page_layout = abi->GetPageLayout(page_idx);
-    size_t num_chunks = SharedMemoryABI::GetNumChunksForLayout(page_layout);
-    for (size_t chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++) {
-      auto chunk_state = abi->GetChunkState(page_idx, chunk_idx);
-      ASSERT_TRUE(chunk_state == SharedMemoryABI::kChunkFree ||
-                  chunk_state == SharedMemoryABI::kChunkComplete);
-      auto chunk = abi->TryAcquireChunkForReading(page_idx, chunk_idx);
-      if (!chunk.is_valid())
-        continue;
-      packets_count += chunk.header()->packets.load().count;
-    }
+  std::vector<std::string> packets = GetPacketsFromShmemAndPatches();
+  ASSERT_THAT(packets, SizeIs(kNumPackets));
+  for (size_t i = 0; i < kNumPackets; i++) {
+    protos::gen::TracePacket packet;
+    packet.ParseFromString(packets[i]);
+    EXPECT_EQ(packet.for_testing().str(), "foobar " + std::to_string(i));
   }
-  EXPECT_EQ(packets_count, kNumPackets);
-  // TODO(primiano): check also the content of the packets decoding the protos.
 }
 
 TEST_P(TraceWriterImplTest, FragmentingPacketWithProducerAndServicePatching) {
   const BufferID kBufId = 42;
   std::unique_ptr<TraceWriter> writer = arbiter_->CreateTraceWriter(kBufId);
 
-  // Write a packet that's guaranteed to span more than a single chunk, but less
-  // than two chunks.
+  // Write a packet that's guaranteed to span more than a single chunk, but
+  // less than two chunks.
   auto packet = writer->NewTracePacket();
   size_t chunk_size = page_size() / 4;
   std::string large_string(chunk_size, 'x');
@@ -111,15 +219,14 @@
 
   // First chunk should be committed.
   arbiter_->FlushPendingCommitDataRequests();
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].target_buffer(), kBufId);
-  EXPECT_THAT(last_commit.chunks_to_patch(), SizeIs(0));
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].target_buffer(), kBufId);
+  EXPECT_THAT(last_commit_.chunks_to_patch(), SizeIs(0));
 
-  // We will simulate a batching cycle by first setting the batching period to a
-  // very large value and then force-flushing when we are done writing data.
+  // We will simulate a batching cycle by first setting the batching period to
+  // a very large value and then force-flushing when we are done writing data.
   arbiter_->SetDirectSMBPatchingSupportedByService();
   ASSERT_TRUE(arbiter_->EnableDirectSMBPatching());
   arbiter_->SetBatchCommitsDuration(UINT32_MAX);
@@ -145,8 +252,8 @@
   SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
 
   // The first allocated chunk should be complete but need patching, since the
-  // packet extended past the chunk and no patches for the packet size or string
-  // field size were applied yet.
+  // packet extended past the chunk and no patches for the packet size or
+  // string field size were applied yet.
   ASSERT_EQ(abi->GetChunkState(0u, 0u), SharedMemoryABI::kChunkComplete);
   auto chunk = abi->TryAcquireChunkForReading(0u, 0u);
   ASSERT_TRUE(chunk.is_valid());
@@ -157,19 +264,19 @@
               SharedMemoryABI::ChunkHeader::kLastPacketContinuesOnNextChunk);
 
   // Verify that a patch for the first chunk was sent to the service.
-  ASSERT_THAT(last_commit.chunks_to_patch(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].writer_id(), writer->writer_id());
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].target_buffer(), kBufId);
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].chunk_id(),
+  ASSERT_THAT(last_commit_.chunks_to_patch(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].writer_id(), writer->writer_id());
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].target_buffer(), kBufId);
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].chunk_id(),
             chunk.header()->chunk_id.load());
-  EXPECT_FALSE(last_commit.chunks_to_patch()[0].has_more_patches());
-  EXPECT_THAT(last_commit.chunks_to_patch()[0].patches(), SizeIs(1));
+  EXPECT_FALSE(last_commit_.chunks_to_patch()[0].has_more_patches());
+  EXPECT_THAT(last_commit_.chunks_to_patch()[0].patches(), SizeIs(1));
 
   // Verify that the second chunk was committed.
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 1u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].target_buffer(), kBufId);
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 1u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].target_buffer(), kBufId);
 
   // The second chunk should be in a complete state and should not need
   // patching, as the patches to it should have been applied in the producer.
@@ -184,9 +291,9 @@
 }
 
 TEST_P(TraceWriterImplTest, FragmentingPacketWithoutEnablingProducerPatching) {
-  // We will simulate a batching cycle by first setting the batching period to a
-  // very large value and will force flush to simulate a flush happening when we
-  // believe it should - in this case when a patch is encountered.
+  // We will simulate a batching cycle by first setting the batching period to
+  // a very large value and will force flush to simulate a flush happening
+  // when we believe it should - in this case when a patch is encountered.
   //
   // Note: direct producer-side patching should be disabled by default.
   arbiter_->SetBatchCommitsDuration(UINT32_MAX);
@@ -207,8 +314,8 @@
   arbiter_->FlushPendingCommitDataRequests();
 
   // The first allocated chunk should be complete but need patching, since the
-  // packet extended past the chunk and no patches for the packet size or string
-  // field size were applied in the producer.
+  // packet extended past the chunk and no patches for the packet size or
+  // string field size were applied in the producer.
   SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
   ASSERT_EQ(abi->GetChunkState(0u, 0u), SharedMemoryABI::kChunkComplete);
   auto chunk = abi->TryAcquireChunkForReading(0u, 0u);
@@ -220,25 +327,24 @@
               SharedMemoryABI::ChunkHeader::kLastPacketContinuesOnNextChunk);
 
   // The first chunk was committed.
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].target_buffer(), kBufId);
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].target_buffer(), kBufId);
 
   // The patches for the first chunk were committed.
-  ASSERT_THAT(last_commit.chunks_to_patch(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].writer_id(), writer->writer_id());
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].target_buffer(), kBufId);
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].chunk_id(),
+  ASSERT_THAT(last_commit_.chunks_to_patch(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].writer_id(), writer->writer_id());
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].target_buffer(), kBufId);
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].chunk_id(),
             chunk.header()->chunk_id.load());
-  EXPECT_FALSE(last_commit.chunks_to_patch()[0].has_more_patches());
-  EXPECT_THAT(last_commit.chunks_to_patch()[0].patches(), SizeIs(1));
+  EXPECT_FALSE(last_commit_.chunks_to_patch()[0].has_more_patches());
+  EXPECT_THAT(last_commit_.chunks_to_patch()[0].patches(), SizeIs(1));
 }
 
-// Sets up a scenario in which the SMB is exhausted and TraceWriter fails to get
-// a new chunk while fragmenting a packet. Verifies that data is dropped until
-// the SMB is freed up and TraceWriter can get a new chunk.
+// Sets up a scenario in which the SMB is exhausted and TraceWriter fails to
+// get a new chunk while fragmenting a packet. Verifies that data is dropped
+// until the SMB is freed up and TraceWriter can get a new chunk.
 TEST_P(TraceWriterImplTest, FragmentingPacketWhileBufferExhausted) {
   const BufferID kBufId = 42;
   std::unique_ptr<TraceWriter> writer =
@@ -260,8 +366,8 @@
                      ->drop_packets_for_testing());
   }
 
-  // Write a packet that's guaranteed to span more than a single chunk, causing
-  // |writer| to attempt to acquire a new chunk but fail to do so.
+  // Write a packet that's guaranteed to span more than a single chunk,
+  // causing |writer| to attempt to acquire a new chunk but fail to do so.
   auto packet2 = writer->NewTracePacket();
   size_t chunk_size = page_size() / 4;
   std::string large_string(chunk_size, 'x');
@@ -272,12 +378,11 @@
 
   // First chunk should be committed.
   arbiter_->FlushPendingCommitDataRequests();
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].target_buffer(), kBufId);
-  EXPECT_THAT(last_commit.chunks_to_patch(), SizeIs(0));
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].target_buffer(), kBufId);
+  EXPECT_THAT(last_commit_.chunks_to_patch(), SizeIs(0));
 
   // It should not need patching and not have the continuation flag set.
   SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
@@ -307,18 +412,19 @@
   EXPECT_FALSE(reinterpret_cast<TraceWriterImpl*>(writer.get())
                    ->drop_packets_for_testing());
 
-  // The first packet in the chunk should have the previous_packet_dropped flag
-  // set, so shouldn't be empty.
+  // The first packet in the chunk should have the previous_packet_dropped
+  // flag set, so shouldn't be empty.
   EXPECT_GT(packet4->Finalize(), 0u);
 
   // Flushing the writer causes the chunk to be released again.
   writer->Flush();
-  EXPECT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
-  EXPECT_THAT(last_commit.chunks_to_patch(), SizeIs(0));
+  EXPECT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
+  EXPECT_THAT(last_commit_.chunks_to_patch(), SizeIs(0));
 
-  // Chunk should contain only |packet4| and not have any continuation flag set.
+  // Chunk should contain only |packet4| and not have any continuation flag
+  // set.
   ASSERT_EQ(abi->GetChunkState(0u, 0u), SharedMemoryABI::kChunkComplete);
   chunk = abi->TryAcquireChunkForReading(0u, 0u);
   ASSERT_TRUE(chunk.is_valid());
@@ -333,8 +439,8 @@
 }
 
 // Verifies that a TraceWriter that is flushed before the SMB is full and then
-// acquires a garbage chunk later recovers and writes a previous_packet_dropped
-// marker into the trace.
+// acquires a garbage chunk later recovers and writes a
+// previous_packet_dropped marker into the trace.
 TEST_P(TraceWriterImplTest, FlushBeforeBufferExhausted) {
   const BufferID kBufId = 42;
   std::unique_ptr<TraceWriter> writer =
@@ -352,10 +458,9 @@
 
   // First chunk should be committed. Don't release it as free just yet.
   arbiter_->FlushPendingCommitDataRequests();
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
 
   // Grab all the remaining chunks in the SMB in new writers.
   std::array<std::unique_ptr<TraceWriter>, kNumPages * 4 - 1> other_writers;
@@ -402,18 +507,19 @@
   EXPECT_FALSE(reinterpret_cast<TraceWriterImpl*>(writer.get())
                    ->drop_packets_for_testing());
 
-  // The first packet in the chunk should have the previous_packet_dropped flag
-  // set, so shouldn't be empty.
+  // The first packet in the chunk should have the previous_packet_dropped
+  // flag set, so shouldn't be empty.
   EXPECT_GT(packet4->Finalize(), 0u);
 
   // Flushing the writer causes the chunk to be released again.
   writer->Flush();
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_move()[0].page(), 0u);
-  EXPECT_EQ(last_commit.chunks_to_move()[0].chunk(), 0u);
-  EXPECT_THAT(last_commit.chunks_to_patch(), SizeIs(0));
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].page(), 0u);
+  EXPECT_EQ(last_commit_.chunks_to_move()[0].chunk(), 0u);
+  EXPECT_THAT(last_commit_.chunks_to_patch(), SizeIs(0));
 
-  // Chunk should contain only |packet4| and not have any continuation flag set.
+  // Chunk should contain only |packet4| and not have any continuation flag
+  // set.
   ASSERT_EQ(SharedMemoryABI::kChunkComplete, abi->GetChunkState(0u, 0u));
   chunk = abi->TryAcquireChunkForReading(0u, 0u);
   ASSERT_TRUE(chunk.is_valid());
@@ -427,9 +533,9 @@
                SharedMemoryABI::ChunkHeader::kLastPacketContinuesOnNextChunk);
 }
 
-// Regression test that verifies that flushing a TraceWriter while a fragmented
-// packet still has uncommitted patches doesn't hit a DCHECK / crash the writer
-// thread.
+// Regression test that verifies that flushing a TraceWriter while a
+// fragmented packet still has uncommitted patches doesn't hit a DCHECK /
+// crash the writer thread.
 TEST_P(TraceWriterImplTest, FlushAfterFragmentingPacketWhileBufferExhausted) {
   const BufferID kBufId = 42;
   std::unique_ptr<TraceWriter> writer =
@@ -464,11 +570,10 @@
 
   // First two chunks should be committed.
   arbiter_->FlushPendingCommitDataRequests();
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_move(), SizeIs(2));
+  ASSERT_THAT(last_commit_.chunks_to_move(), SizeIs(2));
 
-  // Flushing should succeed, even though some patches are still in the writer's
-  // patch list.
+  // Flushing should succeed, even though some patches are still in the
+  // writer's patch list.
   packet2->Finalize();
   writer->Flush();
 }
@@ -484,11 +589,11 @@
   }
 
   EXPECT_CALL(flush_cb, Call).Times(0);
-  ASSERT_FALSE(fake_producer_endpoint_.last_commit_data_callback);
+  ASSERT_FALSE(last_commit_callback_);
   writer->Flush(flush_cb.AsStdFunction());
-  ASSERT_TRUE(fake_producer_endpoint_.last_commit_data_callback);
+  ASSERT_TRUE(last_commit_callback_);
   EXPECT_CALL(flush_cb, Call).Times(1);
-  fake_producer_endpoint_.last_commit_data_callback();
+  last_commit_callback_();
 }
 
 TEST_P(TraceWriterImplTest, NestedMsgsPatches) {
@@ -539,12 +644,11 @@
 
   arbiter_->FlushPendingCommitDataRequests();
 
-  const auto& last_commit = fake_producer_endpoint_.last_commit_data_request;
-  ASSERT_THAT(last_commit.chunks_to_patch(), SizeIs(1));
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].writer_id(), writer->writer_id());
-  EXPECT_EQ(last_commit.chunks_to_patch()[0].target_buffer(), kBufId);
-  EXPECT_FALSE(last_commit.chunks_to_patch()[0].has_more_patches());
-  EXPECT_THAT(last_commit.chunks_to_patch()[0].patches(), SizeIs(3));
+  ASSERT_THAT(last_commit_.chunks_to_patch(), SizeIs(1));
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].writer_id(), writer->writer_id());
+  EXPECT_EQ(last_commit_.chunks_to_patch()[0].target_buffer(), kBufId);
+  EXPECT_FALSE(last_commit_.chunks_to_patch()[0].has_more_patches());
+  EXPECT_THAT(last_commit_.chunks_to_patch()[0].patches(), SizeIs(3));
 }
 
 // TODO(primiano): add multi-writer test.
diff --git a/src/tracing/test/BUILD.gn b/src/tracing/test/BUILD.gn
index fc63b18..78b1d6c 100644
--- a/src/tracing/test/BUILD.gn
+++ b/src/tracing/test/BUILD.gn
@@ -50,7 +50,7 @@
   # has no implementation for Windows or NaCL.
   if (!is_win && !is_nacl) {
     sources += [
-      "fake_producer_endpoint.h",
+      "mock_producer_endpoint.h",
       "mock_consumer.cc",
       "mock_consumer.h",
       "mock_producer.cc",
diff --git a/src/tracing/test/fake_producer_endpoint.h b/src/tracing/test/fake_producer_endpoint.h
deleted file mode 100644
index fa75e4a..0000000
--- a/src/tracing/test/fake_producer_endpoint.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#ifndef SRC_TRACING_TEST_FAKE_PRODUCER_ENDPOINT_H_
-#define SRC_TRACING_TEST_FAKE_PRODUCER_ENDPOINT_H_
-
-#include "perfetto/ext/tracing/core/commit_data_request.h"
-#include "perfetto/ext/tracing/core/tracing_service.h"
-
-namespace perfetto {
-
-class FakeProducerEndpoint : public TracingService::ProducerEndpoint {
- public:
-  void RegisterDataSource(const DataSourceDescriptor&) override {}
-  void UpdateDataSource(const DataSourceDescriptor&) override {}
-  void UnregisterDataSource(const std::string&) override {}
-  void RegisterTraceWriter(uint32_t, uint32_t) override {}
-  void UnregisterTraceWriter(uint32_t) override {}
-  void CommitData(const CommitDataRequest& req,
-                  CommitDataCallback callback) override {
-    last_commit_data_request = req;
-    last_commit_data_callback = callback;
-  }
-  void NotifyFlushComplete(FlushRequestID) override {}
-  void NotifyDataSourceStarted(DataSourceInstanceID) override {}
-  void NotifyDataSourceStopped(DataSourceInstanceID) override {}
-  void ActivateTriggers(const std::vector<std::string>&) override {}
-  void Sync(std::function<void()>) override {}
-  SharedMemory* shared_memory() const override { return nullptr; }
-  size_t shared_buffer_page_size_kb() const override { return 0; }
-  std::unique_ptr<TraceWriter> CreateTraceWriter(
-      BufferID,
-      BufferExhaustedPolicy) override {
-    return nullptr;
-  }
-  SharedMemoryArbiter* MaybeSharedMemoryArbiter() override { return nullptr; }
-  bool IsShmemProvidedByProducer() const override { return false; }
-
-  CommitDataRequest last_commit_data_request;
-  CommitDataCallback last_commit_data_callback;
-};
-
-}  // namespace perfetto
-
-#endif  // SRC_TRACING_TEST_FAKE_PRODUCER_ENDPOINT_H_
diff --git a/src/tracing/test/mock_producer_endpoint.h b/src/tracing/test/mock_producer_endpoint.h
new file mode 100644
index 0000000..d3232e7
--- /dev/null
+++ b/src/tracing/test/mock_producer_endpoint.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#ifndef SRC_TRACING_TEST_MOCK_PRODUCER_ENDPOINT_H_
+#define SRC_TRACING_TEST_MOCK_PRODUCER_ENDPOINT_H_
+
+#include "perfetto/ext/tracing/core/tracing_service.h"
+#include "protos/perfetto/common/data_source_descriptor.gen.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+
+class MockProducerEndpoint : public TracingService::ProducerEndpoint {
+ public:
+  MOCK_METHOD1(RegisterDataSource, void(const DataSourceDescriptor&));
+  MOCK_METHOD1(UpdateDataSource, void(const DataSourceDescriptor&));
+  MOCK_METHOD1(UnregisterDataSource, void(const std::string&));
+  MOCK_METHOD2(RegisterTraceWriter, void(uint32_t, uint32_t));
+  MOCK_METHOD1(UnregisterTraceWriter, void(uint32_t));
+  MOCK_METHOD2(CommitData, void(const CommitDataRequest&, CommitDataCallback));
+  MOCK_CONST_METHOD0(shared_memory, SharedMemory*());
+  MOCK_CONST_METHOD0(shared_buffer_page_size_kb, size_t());
+  MOCK_METHOD2(CreateTraceWriter,
+               std::unique_ptr<TraceWriter>(BufferID, BufferExhaustedPolicy));
+  MOCK_METHOD0(MaybeSharedMemoryArbiter, SharedMemoryArbiter*());
+  MOCK_CONST_METHOD0(IsShmemProvidedByProducer, bool());
+  MOCK_METHOD1(NotifyFlushComplete, void(FlushRequestID));
+  MOCK_METHOD1(NotifyDataSourceStarted, void(DataSourceInstanceID));
+  MOCK_METHOD1(NotifyDataSourceStopped, void(DataSourceInstanceID));
+  MOCK_METHOD1(ActivateTriggers, void(const std::vector<std::string>&));
+  MOCK_METHOD1(Sync, void(std::function<void()>));
+};
+
+}  // namespace perfetto
+
+#endif  // SRC_TRACING_TEST_MOCK_PRODUCER_ENDPOINT_H_
diff --git a/tools/record_android_trace b/tools/record_android_trace
index f2931ed..c5fc03a 100755
--- a/tools/record_android_trace
+++ b/tools/record_android_trace
@@ -107,6 +107,9 @@
   help = 'Don\'t run `adb root` run as user (only when sideloading)'
   parser.add_argument('-u', '--user', action='store_true', help=help)
 
+  help = 'Specify the ADB device serial'
+  parser.add_argument('--serial', '-s', default=None, help=help)
+
   grp = parser.add_argument_group(
       'Short options: (only when not using -c/--config)')
 
@@ -144,9 +147,6 @@
   help = 'Can be generated with https://ui.perfetto.dev/#!/record'
   grp.add_argument('-c', '--config', default=None, help=help)
 
-  help = 'Specify the ADB device serial'
-  grp.add_argument('--serial', '-s', default=None, help=help)
-
   args = parser.parse_args()
   args.sideload = args.sideload or args.sideload_path is not None