Indicate whether process disconnected during profiling session.

Bug: 129054982
Change-Id: Icbcab61d0f2a91347da6cab8c432aadcf0ad65c2
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index cf9ce24..761a636 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2469,6 +2469,11 @@
     // This process was not profiled because a concurrent session was active.
     // If this is true, samples will be empty.
     optional bool rejected_concurrent = 4;
+
+    // This process disconnected while it was profiled.
+    // If false, the process outlived the profiling session.
+    optional bool disconnected = 6;
+
     optional ProcessStats stats = 5;
 
     repeated HeapSample samples = 2;
diff --git a/protos/perfetto/trace/profiling/profile_packet.proto b/protos/perfetto/trace/profiling/profile_packet.proto
index d170dd7..3f6294f 100644
--- a/protos/perfetto/trace/profiling/profile_packet.proto
+++ b/protos/perfetto/trace/profiling/profile_packet.proto
@@ -83,6 +83,11 @@
     // This process was not profiled because a concurrent session was active.
     // If this is true, samples will be empty.
     optional bool rejected_concurrent = 4;
+
+    // This process disconnected while it was profiled.
+    // If false, the process outlived the profiling session.
+    optional bool disconnected = 6;
+
     optional ProcessStats stats = 5;
 
     repeated HeapSample samples = 2;
diff --git a/src/profiling/memory/heapprofd_producer.cc b/src/profiling/memory/heapprofd_producer.cc
index 45fc1e8..232927b 100644
--- a/src/profiling/memory/heapprofd_producer.cc
+++ b/src/profiling/memory/heapprofd_producer.cc
@@ -358,6 +358,7 @@
                                ProfilePacket::ProcessHeapSamples* proto) {
       proto->set_pid(static_cast<uint64_t>(pid));
       proto->set_from_startup(from_startup);
+      proto->set_disconnected(process_state.disconnected);
       auto* stats = proto->set_stats();
       stats->set_unwinding_errors(process_state.unwinding_errors);
       stats->set_heap_samples(process_state.heap_samples);
@@ -751,10 +752,18 @@
   }
 }
 
-void HeapprofdProducer::HandleSocketDisconnected(DataSourceInstanceID, pid_t) {
-  // TODO(fmayer): Dump on process disconnect rather than data source
-  // destruction. This prevents us needing to hold onto the bookkeeping data
-  // after the process disconnected.
+void HeapprofdProducer::HandleSocketDisconnected(DataSourceInstanceID id,
+                                                 pid_t pid) {
+  auto it = data_sources_.find(id);
+  if (it == data_sources_.end())
+    return;
+  DataSource& ds = it->second;
+
+  auto process_state_it = ds.process_states.find(pid);
+  if (process_state_it == ds.process_states.end())
+    return;
+  ProcessState& process_state = process_state_it->second;
+  process_state.disconnected = true;
 }
 
 }  // namespace profiling
diff --git a/src/profiling/memory/heapprofd_producer.h b/src/profiling/memory/heapprofd_producer.h
index dcd9062..7e48068 100644
--- a/src/profiling/memory/heapprofd_producer.h
+++ b/src/profiling/memory/heapprofd_producer.h
@@ -144,6 +144,7 @@
 
   struct ProcessState {
     ProcessState(GlobalCallstackTrie* callsites) : heap_tracker(callsites) {}
+    bool disconnected = false;
     uint64_t heap_samples = 0;
     uint64_t map_reparses = 0;
     uint64_t unwinding_errors = 0;