Merge "Rollback DAC_READ_SEARCH capability"
diff --git a/Android.bp b/Android.bp
index de7759d..b9c1996 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@
     "src/protozero/message.cc",
     "src/protozero/message_handle.cc",
     "src/protozero/proto_utils.cc",
+    "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
     "src/traced/probes/filesystem/fs_mount.cc",
     "src/traced/probes/filesystem/inode_file_data_source.cc",
@@ -77,6 +78,7 @@
     "src/tracing/core/data_source_descriptor.cc",
     "src/tracing/core/ftrace_config.cc",
     "src/tracing/core/id_allocator.cc",
+    "src/tracing/core/null_trace_writer.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/service_impl.cc",
     "src/tracing/core/shared_memory_abi.cc",
@@ -162,6 +164,7 @@
     "src/protozero/message.cc",
     "src/protozero/message_handle.cc",
     "src/protozero/proto_utils.cc",
+    "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
     "src/tracing/core/chrome_config.cc",
     "src/tracing/core/commit_data_request.cc",
@@ -169,6 +172,7 @@
     "src/tracing/core/data_source_descriptor.cc",
     "src/tracing/core/ftrace_config.cc",
     "src/tracing/core/id_allocator.cc",
+    "src/tracing/core/null_trace_writer.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/service_impl.cc",
     "src/tracing/core/shared_memory_abi.cc",
@@ -284,7 +288,6 @@
     "src/ftrace_reader/proto_translation_table.cc",
     "src/ftrace_reader/test/cpu_reader_support.cc",
     "src/ftrace_reader/test/scattered_stream_delegate_for_testing.cc",
-    "src/ftrace_reader/test/scattered_stream_null_delegate.cc",
     "src/ipc/buffered_frame_deserializer.cc",
     "src/ipc/client_impl.cc",
     "src/ipc/deferred.cc",
@@ -296,6 +299,7 @@
     "src/protozero/message.cc",
     "src/protozero/message_handle.cc",
     "src/protozero/proto_utils.cc",
+    "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
     "src/traced/probes/filesystem/fs_mount.cc",
     "src/traced/probes/filesystem/inode_file_data_source.cc",
@@ -310,6 +314,7 @@
     "src/tracing/core/data_source_descriptor.cc",
     "src/tracing/core/ftrace_config.cc",
     "src/tracing/core/id_allocator.cc",
+    "src/tracing/core/null_trace_writer.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/service_impl.cc",
     "src/tracing/core/shared_memory_abi.cc",
@@ -3119,6 +3124,7 @@
     "src/protozero/message.cc",
     "src/protozero/message_handle.cc",
     "src/protozero/proto_utils.cc",
+    "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
     "src/tracing/core/chrome_config.cc",
     "src/tracing/core/commit_data_request.cc",
@@ -3126,6 +3132,7 @@
     "src/tracing/core/data_source_descriptor.cc",
     "src/tracing/core/ftrace_config.cc",
     "src/tracing/core/id_allocator.cc",
+    "src/tracing/core/null_trace_writer.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/service_impl.cc",
     "src/tracing/core/shared_memory_abi.cc",
@@ -3305,7 +3312,6 @@
     "src/ftrace_reader/proto_translation_table_unittest.cc",
     "src/ftrace_reader/test/cpu_reader_support.cc",
     "src/ftrace_reader/test/scattered_stream_delegate_for_testing.cc",
-    "src/ftrace_reader/test/scattered_stream_null_delegate.cc",
     "src/ipc/buffered_frame_deserializer.cc",
     "src/ipc/buffered_frame_deserializer_unittest.cc",
     "src/ipc/client_impl.cc",
@@ -3329,6 +3335,7 @@
     "src/protozero/message_unittest.cc",
     "src/protozero/proto_utils.cc",
     "src/protozero/proto_utils_unittest.cc",
+    "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
     "src/protozero/scattered_stream_writer_unittest.cc",
     "src/protozero/test/fake_scattered_buffer.cc",
@@ -3352,6 +3359,8 @@
     "src/tracing/core/ftrace_config.cc",
     "src/tracing/core/id_allocator.cc",
     "src/tracing/core/id_allocator_unittest.cc",
+    "src/tracing/core/null_trace_writer.cc",
+    "src/tracing/core/null_trace_writer_unittest.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/packet_stream_validator_unittest.cc",
     "src/tracing/core/patch_list_unittest.cc",
diff --git a/include/perfetto/protozero/BUILD.gn b/include/perfetto/protozero/BUILD.gn
index 7b91fe4..b97b137 100644
--- a/include/perfetto/protozero/BUILD.gn
+++ b/include/perfetto/protozero/BUILD.gn
@@ -21,6 +21,7 @@
     "message.h",
     "message_handle.h",
     "proto_field_descriptor.h",
+    "scattered_stream_null_delegate.h",
     "scattered_stream_writer.h",
   ]
 }
diff --git a/src/ftrace_reader/test/scattered_stream_null_delegate.h b/include/perfetto/protozero/scattered_stream_null_delegate.h
similarity index 61%
rename from src/ftrace_reader/test/scattered_stream_null_delegate.h
rename to include/perfetto/protozero/scattered_stream_null_delegate.h
index 41e2bd8..8efb477 100644
--- a/src/ftrace_reader/test/scattered_stream_null_delegate.h
+++ b/include/perfetto/protozero/scattered_stream_null_delegate.h
@@ -14,31 +14,32 @@
  * limitations under the License.
  */
 
-#ifndef SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
-#define SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
+#ifndef INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
+#define INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
 
 #include <memory>
 #include <vector>
 
 #include "perfetto/base/logging.h"
+#include "perfetto/protozero/contiguous_memory_range.h"
 #include "perfetto/protozero/scattered_stream_writer.h"
 
-namespace perfetto {
+namespace protozero {
 
-class ScatteredStreamNullDelegate
-    : public protozero::ScatteredStreamWriter::Delegate {
+class ScatteredStreamWriterNullDelegate
+    : public ScatteredStreamWriter::Delegate {
  public:
-  explicit ScatteredStreamNullDelegate(size_t chunk_size);
-  ~ScatteredStreamNullDelegate() override;
+  explicit ScatteredStreamWriterNullDelegate(size_t chunk_size);
+  ~ScatteredStreamWriterNullDelegate() override;
 
   // protozero::ScatteredStreamWriter::Delegate implementation.
-  protozero::ContiguousMemoryRange GetNewBuffer() override;
+  ContiguousMemoryRange GetNewBuffer() override;
 
  private:
   const size_t chunk_size_;
   std::unique_ptr<uint8_t[]> chunk_;
 };
 
-}  // namespace perfetto
+}  // namespace protozero
 
-#endif  // SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
+#endif  // INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
diff --git a/include/perfetto/tracing/core/shared_memory_arbiter.h b/include/perfetto/tracing/core/shared_memory_arbiter.h
index 9efbba8..2cd336c 100644
--- a/include/perfetto/tracing/core/shared_memory_arbiter.h
+++ b/include/perfetto/tracing/core/shared_memory_arbiter.h
@@ -46,8 +46,7 @@
   // Creates a new TraceWriter and assigns it a new WriterID. The WriterID is
   // written in each chunk header owned by a given TraceWriter and is used by
   // the Service to reconstruct TracePackets written by the same TraceWriter.
-  // Returns nullptr if all WriterID slots are exhausted.
-  // TODO(primiano): instead of nullptr this should return a NoopWriter.
+  // Returns null impl of TraceWriter if all WriterID slots are exhausted.
   virtual std::unique_ptr<TraceWriter> CreateTraceWriter(
       BufferID target_buffer) = 0;
 
diff --git a/src/ftrace_reader/BUILD.gn b/src/ftrace_reader/BUILD.gn
index 7e2a6a6..46de5df 100644
--- a/src/ftrace_reader/BUILD.gn
+++ b/src/ftrace_reader/BUILD.gn
@@ -35,8 +35,6 @@
     "test/cpu_reader_support.h",
     "test/scattered_stream_delegate_for_testing.cc",
     "test/scattered_stream_delegate_for_testing.h",
-    "test/scattered_stream_null_delegate.cc",
-    "test/scattered_stream_null_delegate.h",
   ]
 }
 
diff --git a/src/ftrace_reader/cpu_reader_benchmark.cc b/src/ftrace_reader/cpu_reader_benchmark.cc
index 8771bac..80ca016 100644
--- a/src/ftrace_reader/cpu_reader_benchmark.cc
+++ b/src/ftrace_reader/cpu_reader_benchmark.cc
@@ -16,16 +16,15 @@
 
 #include "src/ftrace_reader/cpu_reader.h"
 
+#include "perfetto/base/utils.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
 #include "perfetto/protozero/scattered_stream_writer.h"
 
 #include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "test/cpu_reader_support.h"
-#include "test/scattered_stream_null_delegate.h"
 
 namespace {
 
-constexpr size_t kPageSize = 4096;
-
 perfetto::ExamplePage g_full_page_sched_switch{
     "synthetic",
     R"(
@@ -293,7 +292,8 @@
 using perfetto::ExamplePage;
 using perfetto::EventFilter;
 using perfetto::ProtoTranslationTable;
-using perfetto::ScatteredStreamNullDelegate;
+using protozero::ScatteredStreamWriterNullDelegate;
+using protozero::ScatteredStreamWriter;
 using perfetto::GetTable;
 using perfetto::PageFromXxd;
 using perfetto::protos::pbzero::FtraceEventBundle;
@@ -303,8 +303,8 @@
 static void BM_ParsePageFullOfSchedSwitch(benchmark::State& state) {
   const ExamplePage* test_case = &g_full_page_sched_switch;
 
-  ScatteredStreamNullDelegate delegate(kPageSize);
-  protozero::ScatteredStreamWriter stream(&delegate);
+  ScatteredStreamWriterNullDelegate delegate(perfetto::base::kPageSize);
+  ScatteredStreamWriter stream(&delegate);
   FtraceEventBundle writer;
 
   ProtoTranslationTable* table = GetTable(test_case->name);
diff --git a/src/ftrace_reader/cpu_reader_fuzzer.cc b/src/ftrace_reader/cpu_reader_fuzzer.cc
index c41b528..e1ebae1 100644
--- a/src/ftrace_reader/cpu_reader_fuzzer.cc
+++ b/src/ftrace_reader/cpu_reader_fuzzer.cc
@@ -21,11 +21,11 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/base/utils.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
 #include "perfetto/protozero/scattered_stream_writer.h"
 #include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "src/ftrace_reader/cpu_reader.h"
 #include "test/cpu_reader_support.h"
-#include "test/scattered_stream_null_delegate.h"
 
 namespace perfetto {
 namespace {
@@ -39,7 +39,7 @@
 void FuzzCpuReaderParsePage(const uint8_t* data, size_t size);
 
 void FuzzCpuReaderParsePage(const uint8_t* data, size_t size) {
-  ScatteredStreamNullDelegate delegate(base::kPageSize);
+  protozero::ScatteredStreamWriterNullDelegate delegate(base::kPageSize);
   protozero::ScatteredStreamWriter stream(&delegate);
   FtraceEventBundle writer;
 
diff --git a/src/ftrace_reader/test/cpu_reader_support.cc b/src/ftrace_reader/test/cpu_reader_support.cc
index 7554346..0a778ca 100644
--- a/src/ftrace_reader/test/cpu_reader_support.cc
+++ b/src/ftrace_reader/test/cpu_reader_support.cc
@@ -16,6 +16,7 @@
 
 #include "src/ftrace_reader/test/cpu_reader_support.h"
 
+#include "perfetto/base/utils.h"
 #include "src/ftrace_reader/ftrace_procfs.h"
 
 #include <string.h>
@@ -23,8 +24,6 @@
 namespace perfetto {
 namespace {
 
-constexpr size_t kPageSize = 4096;
-
 std::map<std::string, std::unique_ptr<ProtoTranslationTable>>* g_tables;
 
 }  // namespace
@@ -44,9 +43,9 @@
 }
 
 std::unique_ptr<uint8_t[]> PageFromXxd(const std::string& text) {
-  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[kPageSize]);
+  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[base::kPageSize]);
   const char* ptr = text.data();
-  memset(buffer.get(), 0xfa, kPageSize);
+  memset(buffer.get(), 0xfa, base::kPageSize);
   uint8_t* out = buffer.get();
   while (*ptr != '\0') {
     if (*(ptr++) != ':')
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index 0d67278..c7f3d95 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -30,6 +30,7 @@
     "message.cc",
     "message_handle.cc",
     "proto_utils.cc",
+    "scattered_stream_null_delegate.cc",
     "scattered_stream_writer.cc",
   ]
 }
diff --git a/src/ftrace_reader/test/scattered_stream_null_delegate.cc b/src/protozero/scattered_stream_null_delegate.cc
similarity index 60%
rename from src/ftrace_reader/test/scattered_stream_null_delegate.cc
rename to src/protozero/scattered_stream_null_delegate.cc
index 562a3db..3587dba 100644
--- a/src/ftrace_reader/test/scattered_stream_null_delegate.cc
+++ b/src/protozero/scattered_stream_null_delegate.cc
@@ -14,22 +14,24 @@
  * limitations under the License.
  */
 
-#include "src/ftrace_reader/test/scattered_stream_null_delegate.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
 
-namespace perfetto {
+namespace protozero {
 
 // An implementation of ScatteredStreamWriter::Delegate which always returns
-// the same bit of memory (to better measure performance of users of
-// ScatteredStreamWriter without noisy allocations).
-
-ScatteredStreamNullDelegate::ScatteredStreamNullDelegate(size_t chunk_size)
+// the same piece of memory.
+// This is used when we need to no-op the writers (e.g. during teardown or in
+// case of resource exhaustion), avoiding that the clients have to deal with
+// nullptr checks.
+ScatteredStreamWriterNullDelegate::ScatteredStreamWriterNullDelegate(
+    size_t chunk_size)
     : chunk_size_(chunk_size),
       chunk_(std::unique_ptr<uint8_t[]>(new uint8_t[chunk_size_])){};
 
-ScatteredStreamNullDelegate::~ScatteredStreamNullDelegate() {}
+ScatteredStreamWriterNullDelegate::~ScatteredStreamWriterNullDelegate() {}
 
-protozero::ContiguousMemoryRange ScatteredStreamNullDelegate::GetNewBuffer() {
+ContiguousMemoryRange ScatteredStreamWriterNullDelegate::GetNewBuffer() {
   return {chunk_.get(), chunk_.get() + chunk_size_};
 }
 
-}  // namespace perfetto
+}  // namespace protozero
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index eef490d..80aedb4 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -37,6 +37,8 @@
     "core/ftrace_config.cc",
     "core/id_allocator.cc",
     "core/id_allocator.h",
+    "core/null_trace_writer.cc",
+    "core/null_trace_writer.h",
     "core/packet_stream_validator.cc",
     "core/packet_stream_validator.h",
     "core/patch_list.h",
@@ -122,6 +124,7 @@
   ]
   sources = [
     "core/id_allocator_unittest.cc",
+    "core/null_trace_writer_unittest.cc",
     "core/packet_stream_validator_unittest.cc",
     "core/patch_list_unittest.cc",
     "core/service_impl_unittest.cc",
diff --git a/src/tracing/core/null_trace_writer.cc b/src/tracing/core/null_trace_writer.cc
new file mode 100644
index 0000000..36cddf4
--- /dev/null
+++ b/src/tracing/core/null_trace_writer.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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 "src/tracing/core/null_trace_writer.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/utils.h"
+
+#include "perfetto/protozero/message.h"
+
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+NullTraceWriter::NullTraceWriter()
+    : delegate_(base::kPageSize), stream_(&delegate_) {
+  cur_packet_.reset(new protos::pbzero::TracePacket());
+  cur_packet_->Finalize();  // To avoid the DCHECK in NewTracePacket().
+}
+
+NullTraceWriter::~NullTraceWriter() {}
+
+void NullTraceWriter::Flush(std::function<void()> callback) {
+  // Flush() cannot be called in the middle of a TracePacket.
+  PERFETTO_CHECK(cur_packet_->is_finalized());
+
+  if (callback)
+    callback();
+}
+
+NullTraceWriter::TracePacketHandle NullTraceWriter::NewTracePacket() {
+  // If we hit this, the caller is calling NewTracePacket() without having
+  // finalized the previous packet.
+  PERFETTO_DCHECK(cur_packet_->is_finalized());
+  cur_packet_->Reset(&stream_);
+  return TraceWriter::TracePacketHandle(cur_packet_.get());
+}
+
+WriterID NullTraceWriter::writer_id() const {
+  return 0;
+}
+
+}  // namespace perfetto
diff --git a/src/tracing/core/null_trace_writer.h b/src/tracing/core/null_trace_writer.h
new file mode 100644
index 0000000..8f10819
--- /dev/null
+++ b/src/tracing/core/null_trace_writer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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_CORE_NULL_TRACE_WRITER_H_
+#define SRC_TRACING_CORE_NULL_TRACE_WRITER_H_
+
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
+#include "perfetto/tracing/core/trace_writer.h"
+
+namespace perfetto {
+
+// A specialization of TraceWriter which no-ops all the writes routing them
+// into a fixed region of memory
+// See //include/perfetto/tracing/core/trace_writer.h for docs.
+class NullTraceWriter : public TraceWriter {
+ public:
+  NullTraceWriter();
+  ~NullTraceWriter() override;
+
+  // TraceWriter implementation. See documentation in trace_writer.h.
+  // TracePacketHandle is defined in trace_writer.h
+  TracePacketHandle NewTracePacket() override;
+  void Flush(std::function<void()> callback = {}) override;
+  WriterID writer_id() const override;
+
+ private:
+  NullTraceWriter(const NullTraceWriter&) = delete;
+  NullTraceWriter& operator=(const NullTraceWriter&) = delete;
+
+  protozero::ScatteredStreamWriterNullDelegate delegate_;
+  protozero::ScatteredStreamWriter stream_;
+
+  // The packet returned via NewTracePacket(). Its owned by this class,
+  // TracePacketHandle has just a pointer to it.
+  std::unique_ptr<protos::pbzero::TracePacket> cur_packet_;
+};
+
+}  // namespace perfetto
+
+#endif  // SRC_TRACING_CORE_NULL_TRACE_WRITER_H_
diff --git a/src/tracing/core/null_trace_writer_unittest.cc b/src/tracing/core/null_trace_writer_unittest.cc
new file mode 100644
index 0000000..f2d2f54
--- /dev/null
+++ b/src/tracing/core/null_trace_writer_unittest.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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 "src/tracing/core/null_trace_writer.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "perfetto/base/utils.h"
+#include "perfetto/tracing/core/trace_writer.h"
+
+#include "perfetto/trace/test_event.pbzero.h"
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace {
+
+TEST(NullTraceWriterTest, WriterIdIsZero) {
+  NullTraceWriter writer;
+  EXPECT_EQ(writer.writer_id(), 0);
+}
+
+TEST(NullTraceWriterTest, Writing) {
+  NullTraceWriter writer;
+  for (size_t i = 0; i < 3 * base::kPageSize; i++) {
+    auto packet = writer.NewTracePacket();
+    packet->set_for_testing()->set_str("Hello, world!");
+  }
+}
+
+TEST(NullTraceWriterTest, FlushCallbackIsCalled) {
+  NullTraceWriter writer;
+  writer.Flush();
+  bool was_called = false;
+  writer.Flush([&was_called] { was_called = true; });
+  EXPECT_TRUE(was_called);
+}
+
+}  // namespace
+}  // namespace perfetto
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index 04612ee..552898e 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -278,9 +278,9 @@
     const size_t buf_size_bytes = buffer_cfg.size_kb() * 1024u;
     total_buf_size_kb += buffer_cfg.size_kb();
     auto it_and_inserted =
-        buffers_.emplace(global_id, TraceBuffez::Create(buf_size_bytes));
+        buffers_.emplace(global_id, TraceBuffer::Create(buf_size_bytes));
     PERFETTO_DCHECK(it_and_inserted.second);  // buffers_.count(global_id) == 0.
-    std::unique_ptr<TraceBuffez>& trace_buffer = it_and_inserted.first->second;
+    std::unique_ptr<TraceBuffer>& trace_buffer = it_and_inserted.first->second;
     if (!trace_buffer) {
       did_allocate_all_buffers = false;
       break;
@@ -451,7 +451,7 @@
       PERFETTO_DCHECK(false);
       continue;
     }
-    TraceBuffez& tbuf = *tbuf_iter->second;
+    TraceBuffer& tbuf = *tbuf_iter->second;
     tbuf.BeginRead();
     while (!did_hit_threshold) {
       TracePacket packet;
@@ -765,7 +765,7 @@
                                                 const uint8_t* src,
                                                 size_t size) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
-  TraceBuffez* buf = GetBufferByID(buffer_id);
+  TraceBuffer* buf = GetBufferByID(buffer_id);
   if (!buf) {
     PERFETTO_DLOG("Could not find target buffer %" PRIu16
                   " for producer %" PRIu16,
@@ -791,7 +791,7 @@
   for (const auto& chunk : chunks_to_patch) {
     const ChunkID chunk_id = static_cast<ChunkID>(chunk.chunk_id());
     const WriterID writer_id = static_cast<WriterID>(chunk.writer_id());
-    TraceBuffez* buf =
+    TraceBuffer* buf =
         GetBufferByID(static_cast<BufferID>(chunk.target_buffer()));
     static_assert(std::numeric_limits<ChunkID>::max() == kMaxChunkID,
                   "Add a '|| chunk_id > kMaxChunkID' below if this fails");
@@ -804,7 +804,7 @@
     }
     // Speculate on the fact that there are going to be a limited amount of
     // patches per request, so we can allocate the |patches| array on the stack.
-    std::array<TraceBuffez::Patch, 1024> patches;  // Uninitialized.
+    std::array<TraceBuffer::Patch, 1024> patches;  // Uninitialized.
     if (chunk.patches().size() > patches.size()) {
       PERFETTO_DLOG("Too many patches (%zu) batched in the same request",
                     patches.size());
@@ -849,7 +849,7 @@
   return last_producer_id_;
 }
 
-TraceBuffez* ServiceImpl::GetBufferByID(BufferID buffer_id) {
+TraceBuffer* ServiceImpl::GetBufferByID(BufferID buffer_id) {
   auto buf_iter = buffers_.find(buffer_id);
   if (buf_iter == buffers_.end())
     return nullptr;
diff --git a/src/tracing/core/service_impl.h b/src/tracing/core/service_impl.h
index 4f7428c..899b6a6 100644
--- a/src/tracing/core/service_impl.h
+++ b/src/tracing/core/service_impl.h
@@ -46,7 +46,7 @@
 class Producer;
 class SharedMemory;
 class SharedMemoryArbiterImpl;
-class TraceBuffez;
+class TraceBuffer;
 class TraceConfig;
 class TracePacket;
 
@@ -257,7 +257,7 @@
   void MaybeSnapshotClocks(TracingSession*, std::vector<TracePacket>*);
   void MaybeEmitTraceConfig(TracingSession*, std::vector<TracePacket>*);
 
-  TraceBuffez* GetBufferByID(BufferID);
+  TraceBuffer* GetBufferByID(BufferID);
 
   base::TaskRunner* const task_runner_;
   std::unique_ptr<SharedMemory::Factory> shm_factory_;
@@ -278,7 +278,7 @@
 
   std::set<ConsumerEndpointImpl*> consumers_;
   std::map<TracingSessionID, TracingSession> tracing_sessions_;
-  std::map<BufferID, std::unique_ptr<TraceBuffez>> buffers_;
+  std::map<BufferID, std::unique_ptr<TraceBuffer>> buffers_;
 
   bool lockdown_mode_ = false;
 
diff --git a/src/tracing/core/shared_memory_arbiter_impl.cc b/src/tracing/core/shared_memory_arbiter_impl.cc
index c1b7e23..c500936 100644
--- a/src/tracing/core/shared_memory_arbiter_impl.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl.cc
@@ -20,6 +20,7 @@
 #include "perfetto/base/task_runner.h"
 #include "perfetto/tracing/core/commit_data_request.h"
 #include "perfetto/tracing/core/shared_memory.h"
+#include "src/tracing/core/null_trace_writer.h"
 #include "src/tracing/core/trace_writer_impl.h"
 
 #include <limits>
@@ -240,8 +241,10 @@
     std::lock_guard<std::mutex> scoped_lock(lock_);
     id = active_writer_ids_.Allocate();
   }
+  if (!id)
+    return std::unique_ptr<TraceWriter>(new NullTraceWriter());
   return std::unique_ptr<TraceWriter>(
-      id ? new TraceWriterImpl(this, id, target_buffer) : nullptr);
+      new TraceWriterImpl(this, id, target_buffer));
 }
 
 void SharedMemoryArbiterImpl::ReleaseWriterID(WriterID id) {
diff --git a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
index 8505876..a45328c 100644
--- a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
@@ -137,8 +137,9 @@
     ASSERT_TRUE(writers.emplace(writer_id, std::move(writer)).second);
   }
 
-  // A further call should fail as we exhausted writer IDs.
-  ASSERT_EQ(nullptr, arbiter_->CreateTraceWriter(0).get());
+  // A further call should return a null impl of trace writer as we exhausted
+  // writer IDs.
+  ASSERT_EQ(arbiter_->CreateTraceWriter(0)->writer_id(), 0);
 }
 
 // TODO(primiano): add multi-threaded tests.
diff --git a/src/tracing/core/trace_buffer.cc b/src/tracing/core/trace_buffer.cc
index 1a7a554..fb5b7b3 100644
--- a/src/tracing/core/trace_buffer.cc
+++ b/src/tracing/core/trace_buffer.cc
@@ -59,27 +59,27 @@
     SharedMemoryABI::ChunkHeader::kChunkNeedsPatching;
 }  // namespace.
 
-constexpr size_t TraceBuffez::ChunkRecord::kMaxSize;
-constexpr size_t TraceBuffez::InlineChunkHeaderSize = sizeof(ChunkRecord);
+constexpr size_t TraceBuffer::ChunkRecord::kMaxSize;
+constexpr size_t TraceBuffer::InlineChunkHeaderSize = sizeof(ChunkRecord);
 
 // static
-std::unique_ptr<TraceBuffez> TraceBuffez::Create(size_t size_in_bytes) {
-  std::unique_ptr<TraceBuffez> trace_buffer(new TraceBuffez());
+std::unique_ptr<TraceBuffer> TraceBuffer::Create(size_t size_in_bytes) {
+  std::unique_ptr<TraceBuffer> trace_buffer(new TraceBuffer());
   if (!trace_buffer->Initialize(size_in_bytes))
     return nullptr;
   return trace_buffer;
 }
 
-TraceBuffez::TraceBuffez() {
+TraceBuffer::TraceBuffer() {
   // See comments in ChunkRecord for the rationale of this.
   static_assert(sizeof(ChunkRecord) == sizeof(SharedMemoryABI::PageHeader) +
                                            sizeof(SharedMemoryABI::ChunkHeader),
                 "ChunkRecord out of sync with the layout of SharedMemoryABI");
 }
 
-TraceBuffez::~TraceBuffez() = default;
+TraceBuffer::~TraceBuffer() = default;
 
-bool TraceBuffez::Initialize(size_t size) {
+bool TraceBuffer::Initialize(size_t size) {
   static_assert(
       base::kPageSize % sizeof(ChunkRecord) == 0,
       "sizeof(ChunkRecord) must be an integer divider of a page size");
@@ -101,7 +101,7 @@
 // Note: |src| points to a shmem region that is shared with the producer. Assume
 // that the producer is malicious and will change the content of |src|
 // while we execute here. Don't do any processing on it other than memcpy().
-void TraceBuffez::CopyChunkUntrusted(ProducerID producer_id_trusted,
+void TraceBuffer::CopyChunkUntrusted(ProducerID producer_id_trusted,
                                      uid_t producer_uid_trusted,
                                      WriterID writer_id,
                                      ChunkID chunk_id,
@@ -195,7 +195,7 @@
     AddPaddingRecord(padding_size);
 }
 
-size_t TraceBuffez::DeleteNextChunksFor(size_t bytes_to_clear) {
+size_t TraceBuffer::DeleteNextChunksFor(size_t bytes_to_clear) {
   // Find the position of the first chunk which begins at or after
   // (|wptr_| + |bytes|). Note that such a chunk might not exist and we might
   // either reach the end of the buffer or a zeroed region of the buffer.
@@ -247,7 +247,7 @@
   return next_chunk_ptr - search_end;
 }
 
-void TraceBuffez::AddPaddingRecord(size_t size) {
+void TraceBuffer::AddPaddingRecord(size_t size) {
   PERFETTO_DCHECK(size >= sizeof(ChunkRecord) && size <= ChunkRecord::kMaxSize);
   ChunkRecord record(size);
   record.is_padding = 1;
@@ -257,7 +257,7 @@
   // |wptr_| is deliberately not advanced when writing a padding record.
 }
 
-bool TraceBuffez::TryPatchChunkContents(ProducerID producer_id,
+bool TraceBuffer::TryPatchChunkContents(ProducerID producer_id,
                                         WriterID writer_id,
                                         ChunkID chunk_id,
                                         const Patch* patches,
@@ -320,14 +320,14 @@
   return true;
 }
 
-void TraceBuffez::BeginRead() {
+void TraceBuffer::BeginRead() {
   read_iter_ = GetReadIterForSequence(index_.begin());
 #if PERFETTO_DCHECK_IS_ON()
   changed_since_last_read_ = false;
 #endif
 }
 
-TraceBuffez::SequenceIterator TraceBuffez::GetReadIterForSequence(
+TraceBuffer::SequenceIterator TraceBuffer::GetReadIterForSequence(
     ChunkMap::iterator seq_begin) {
   SequenceIterator iter;
   iter.seq_begin = seq_begin;
@@ -369,7 +369,7 @@
   return iter;
 }
 
-void TraceBuffez::SequenceIterator::MoveNext() {
+void TraceBuffer::SequenceIterator::MoveNext() {
   // Note: |seq_begin| might be == |seq_end|.
   if (cur == seq_end || cur->first.chunk_id == wrapping_id) {
     cur = seq_end;
@@ -379,7 +379,7 @@
     cur = seq_begin;
 }
 
-bool TraceBuffez::ReadNextTracePacket(TracePacket* packet,
+bool TraceBuffer::ReadNextTracePacket(TracePacket* packet,
                                       uid_t* producer_uid) {
   // Note: MoveNext() moves only within the next chunk within the same
   // {ProducerID, WriterID} sequence. Here we want to:
@@ -523,7 +523,7 @@
   }    // for(;;MoveNext()) [iterate over chunks].
 }
 
-TraceBuffez::ReadAheadResult TraceBuffez::ReadAhead(TracePacket* packet) {
+TraceBuffer::ReadAheadResult TraceBuffer::ReadAhead(TracePacket* packet) {
   static_assert(static_cast<ChunkID>(kMaxChunkID + 1) == 0,
                 "relying on kMaxChunkID to wrap naturally");
   TRACE_BUFFER_DLOG(" readahead start @ chunk %u", read_iter_.chunk_id());
@@ -600,7 +600,7 @@
   return ReadAheadResult::kFailedMoveToNextSequence;
 }
 
-bool TraceBuffez::ReadNextPacketInChunk(ChunkMeta* chunk_meta,
+bool TraceBuffer::ReadNextPacketInChunk(ChunkMeta* chunk_meta,
                                         TracePacket* packet) {
   PERFETTO_DCHECK(chunk_meta->num_fragments_read < chunk_meta->num_fragments);
   PERFETTO_DCHECK(!(chunk_meta->flags & kChunkNeedsPatching));
diff --git a/src/tracing/core/trace_buffer.h b/src/tracing/core/trace_buffer.h
index 2aea918..a66a4db 100644
--- a/src/tracing/core/trace_buffer.h
+++ b/src/tracing/core/trace_buffer.h
@@ -123,10 +123,7 @@
 // Reads guarantee that packets for the same sequence are read in FIFO order
 // (according to their ChunkID), but don't give any guarantee about the read
 // order of packets from different sequences (see ReadPacket() comments below).
-//
-// TODO(primiano): the name of this class is deliberately typo-ed as a temporary
-// situation until we replace TraceBuffer within service_impl.cc.
-class TraceBuffez {
+class TraceBuffer {
  public:
   static const size_t InlineChunkHeaderSize;  // For test/fake_packet.{cc,h}.
 
@@ -151,9 +148,9 @@
   };
 
   // Can return nullptr if the memory allocation fails.
-  static std::unique_ptr<TraceBuffez> Create(size_t size_in_bytes);
+  static std::unique_ptr<TraceBuffer> Create(size_t size_in_bytes);
 
-  ~TraceBuffez();
+  ~TraceBuffer();
 
   // Copies a Chunk from a producer Shared Memory Buffer into the trace buffer.
   // |src| points to the first packet in the SharedMemoryABI's chunk shared
@@ -399,9 +396,9 @@
     kFailedStayOnSameSequence,
   };
 
-  TraceBuffez();
-  TraceBuffez(const TraceBuffez&) = delete;
-  TraceBuffez& operator=(const TraceBuffez&) = delete;
+  TraceBuffer();
+  TraceBuffer(const TraceBuffer&) = delete;
+  TraceBuffer& operator=(const TraceBuffer&) = delete;
 
   bool Initialize(size_t size);
 
diff --git a/src/tracing/core/trace_buffer_unittest.cc b/src/tracing/core/trace_buffer_unittest.cc
index c12c8e3..3031b3b 100644
--- a/src/tracing/core/trace_buffer_unittest.cc
+++ b/src/tracing/core/trace_buffer_unittest.cc
@@ -39,9 +39,9 @@
 
 class TraceBufferTest : public testing::Test {
  public:
-  using SequenceIterator = TraceBuffez::SequenceIterator;
-  using ChunkMetaKey = TraceBuffez::ChunkMeta::Key;
-  using ChunkRecord = TraceBuffez::ChunkRecord;
+  using SequenceIterator = TraceBuffer::SequenceIterator;
+  using ChunkMetaKey = TraceBuffer::ChunkMeta::Key;
+  using ChunkRecord = TraceBuffer::ChunkRecord;
 
   static constexpr uint8_t kContFromPrevChunk =
       SharedMemoryABI::ChunkHeader::kFirstPacketContinuesFromPrevChunk;
@@ -55,14 +55,14 @@
   }
 
   void ResetBuffer(size_t size_) {
-    trace_buffer_ = TraceBuffez::Create(size_);
+    trace_buffer_ = TraceBuffer::Create(size_);
     ASSERT_TRUE(trace_buffer_);
   }
 
   bool TryPatchChunkContents(ProducerID p,
                              WriterID w,
                              ChunkID c,
-                             std::vector<TraceBuffez::Patch> patches,
+                             std::vector<TraceBuffer::Patch> patches,
                              bool other_patches_pending = false) {
     return trace_buffer_->TryPatchChunkContents(
         p, w, c, patches.data(), patches.size(), other_patches_pending);
@@ -109,7 +109,7 @@
   }
 
   SequenceIterator GetReadIterForSequence(ProducerID p, WriterID w) {
-    TraceBuffez::ChunkMeta::Key key(p, w, 0);
+    TraceBuffer::ChunkMeta::Key key(p, w, 0);
     return trace_buffer_->GetReadIterForSequence(
         trace_buffer_->index_.lower_bound(key));
   }
@@ -126,11 +126,11 @@
     return keys;
   }
 
-  TraceBuffez* trace_buffer() { return trace_buffer_.get(); }
+  TraceBuffer* trace_buffer() { return trace_buffer_.get(); }
   size_t size_to_end() { return trace_buffer_->size_to_end(); }
 
  private:
-  std::unique_ptr<TraceBuffez> trace_buffer_;
+  std::unique_ptr<TraceBuffer> trace_buffer_;
 };
 
 // ----------------------
diff --git a/src/tracing/core/trace_writer_impl.cc b/src/tracing/core/trace_writer_impl.cc
index ded5909..bfdf1f4 100644
--- a/src/tracing/core/trace_writer_impl.cc
+++ b/src/tracing/core/trace_writer_impl.cc
@@ -197,7 +197,7 @@
 
 WriterID TraceWriterImpl::writer_id() const {
   return id_;
-};
+}
 
 // Base class ctor/dtor definition.
 TraceWriter::TraceWriter() = default;
diff --git a/src/tracing/core/trace_writer_impl.h b/src/tracing/core/trace_writer_impl.h
index 28fa95f..3ba878d 100644
--- a/src/tracing/core/trace_writer_impl.h
+++ b/src/tracing/core/trace_writer_impl.h
@@ -36,7 +36,7 @@
   TraceWriterImpl(SharedMemoryArbiterImpl*, WriterID, BufferID);
   ~TraceWriterImpl() override;
 
-  // TraceWriter implementation. See documentation in trace_writer.h .
+  // TraceWriter implementation. See documentation in trace_writer.h.
   TracePacketHandle NewTracePacket() override;
   void Flush(std::function<void()> callback = {}) override;
   WriterID writer_id() const override;
diff --git a/src/tracing/test/fake_packet.cc b/src/tracing/test/fake_packet.cc
index fd5ca05..2a254da 100644
--- a/src/tracing/test/fake_packet.cc
+++ b/src/tracing/test/fake_packet.cc
@@ -103,7 +103,7 @@
             << packet.payload() << "\"}";
 }
 
-FakeChunk::FakeChunk(TraceBuffez* t, ProducerID p, WriterID w, ChunkID c)
+FakeChunk::FakeChunk(TraceBuffer* t, ProducerID p, WriterID w, ChunkID c)
     : trace_buffer_{t}, producer_id{p}, writer_id{w}, chunk_id{c} {}
 
 FakeChunk& FakeChunk::AddPacket(size_t size, char seed, uint8_t packet_flag) {
@@ -141,7 +141,7 @@
   trace_buffer_->CopyChunkUntrusted(producer_id, uid, writer_id, chunk_id,
                                     num_packets, flags, data.data(),
                                     data.size());
-  return data.size() + TraceBuffez::InlineChunkHeaderSize;
+  return data.size() + TraceBuffer::InlineChunkHeaderSize;
 }
 
 }  // namespace perfetto
diff --git a/src/tracing/test/fake_packet.h b/src/tracing/test/fake_packet.h
index daab5e8..b3e56d8 100644
--- a/src/tracing/test/fake_packet.h
+++ b/src/tracing/test/fake_packet.h
@@ -28,7 +28,7 @@
 
 namespace perfetto {
 
-class TraceBuffez;
+class TraceBuffer;
 
 class FakePacketFragment {
  public:
@@ -51,7 +51,7 @@
 
 class FakeChunk {
  public:
-  FakeChunk(TraceBuffez* t, ProducerID p, WriterID w, ChunkID c);
+  FakeChunk(TraceBuffer* t, ProducerID p, WriterID w, ChunkID c);
 
   // Appends a packet of exactly |size| bytes (including the varint header
   // that states the size of the packet itself. The payload of the packet is
@@ -70,7 +70,7 @@
   size_t CopyIntoTraceBuffer();
 
  private:
-  TraceBuffez* trace_buffer_;
+  TraceBuffer* trace_buffer_;
   ProducerID producer_id;
   WriterID writer_id;
   ChunkID chunk_id;