Reduce ProducerID 64 -> 16 bits

This saves some space in the upcoming ChunkRecord in TraceBuffer.
We are not going to be able to deal with > 64k producers anyways
as each of them requires at least one file descriptor.

Also this fixes a minor bug in the page_owners initialization
in TraceBuffer::Create().

Bug: 73612642
Test: perfetto_unittest --gtest_filter=ServiceImplTest.ProducerIDWrapping
Change-Id: Id105760ad8cfbb6f0e8ab8edc65954d5ed3ae395
diff --git a/src/tracing/core/service_impl_unittest.cc b/src/tracing/core/service_impl_unittest.cc
index 3ab0b11..7c9f0a4 100644
--- a/src/tracing/core/service_impl_unittest.cc
+++ b/src/tracing/core/service_impl_unittest.cc
@@ -32,6 +32,7 @@
 namespace perfetto {
 using ::testing::_;
 using ::testing::InSequence;
+using ::testing::Invoke;
 using ::testing::Mock;
 
 namespace {
@@ -134,7 +135,6 @@
 
   ASSERT_EQ(0u, svc->num_producers());
 }
-
 TEST_F(ServiceImplTest, EnableAndDisableTracing) {
   MockProducer mock_producer;
   std::unique_ptr<Service::ProducerEndpoint> producer_endpoint =
@@ -267,4 +267,67 @@
   Mock::VerifyAndClearExpectations(&mock_consumer);
 }
 
+TEST_F(ServiceImplTest, ProducerIDWrapping) {
+  base::TestTaskRunner task_runner;
+  auto shm_factory =
+      std::unique_ptr<SharedMemory::Factory>(new TestSharedMemory::Factory());
+  std::unique_ptr<ServiceImpl> svc(static_cast<ServiceImpl*>(
+      Service::CreateInstance(std::move(shm_factory), &task_runner).release()));
+
+  std::map<ProducerID, std::pair<std::unique_ptr<MockProducer>,
+                                 std::unique_ptr<Service::ProducerEndpoint>>>
+      producers;
+
+  auto ConnectProducerAndWait = [&task_runner, &svc, &producers]() {
+    char checkpoint_name[32];
+    static int checkpoint_num = 0;
+    sprintf(checkpoint_name, "on_connect_%d", checkpoint_num++);
+    auto on_connect = task_runner.CreateCheckpoint(checkpoint_name);
+    std::unique_ptr<MockProducer> producer(new MockProducer());
+    std::unique_ptr<Service::ProducerEndpoint> producer_endpoint =
+        svc->ConnectProducer(producer.get(), 123u /* uid */);
+    EXPECT_CALL(*producer, OnConnect()).WillOnce(Invoke(on_connect));
+    task_runner.RunUntilCheckpoint(checkpoint_name);
+    EXPECT_EQ(&*producer_endpoint, svc->GetProducer(svc->last_producer_id_));
+    const ProducerID pr_id = svc->last_producer_id_;
+    producers.emplace(pr_id, std::make_pair(std::move(producer),
+                                            std::move(producer_endpoint)));
+    return pr_id;
+  };
+
+  auto DisconnectProducerAndWait = [&task_runner,
+                                    &producers](ProducerID pr_id) {
+    char checkpoint_name[32];
+    static int checkpoint_num = 0;
+    sprintf(checkpoint_name, "on_disconnect_%d", checkpoint_num++);
+    auto on_disconnect = task_runner.CreateCheckpoint(checkpoint_name);
+    auto it = producers.find(pr_id);
+    PERFETTO_CHECK(it != producers.end());
+    EXPECT_CALL(*it->second.first, OnDisconnect())
+        .WillOnce(Invoke(on_disconnect));
+    producers.erase(pr_id);
+    task_runner.RunUntilCheckpoint(checkpoint_name);
+  };
+
+  // Connect producers 1-4.
+  for (ProducerID i = 1; i <= 4; i++)
+    ASSERT_EQ(i, ConnectProducerAndWait());
+
+  // Disconnect producers 1,3.
+  DisconnectProducerAndWait(1);
+  DisconnectProducerAndWait(3);
+
+  svc->last_producer_id_ = kMaxProducerID - 1;
+  ASSERT_EQ(kMaxProducerID, ConnectProducerAndWait());
+  ASSERT_EQ(1u, ConnectProducerAndWait());
+  ASSERT_EQ(3u, ConnectProducerAndWait());
+  ASSERT_EQ(5u, ConnectProducerAndWait());
+  ASSERT_EQ(6u, ConnectProducerAndWait());
+
+  // Disconnect all producers to mute spurious callbacks.
+  DisconnectProducerAndWait(kMaxProducerID);
+  for (ProducerID i = 1; i <= 6; i++)
+    DisconnectProducerAndWait(i);
+}
+
 }  // namespace perfetto