Merge "trace_processor: add copy/move constructors to potentially fix compile"
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index 0b2efbf..0f08b42 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -38,25 +38,6 @@
 #define PERFETTO_NO_INLINE
 #endif
 
-// TODO(lalitm): is_trivially_constructible is currently not available
-// in some environments we build in. Reenable when that environment supports
-// this.
-#if defined(__GLIBCXX__)
-#define PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(T) true
-#else
-#define PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(T) \
-  std::is_trivially_constructible<T>::value
-#endif
-
-// TODO(lalitm): is_trivially_copyable is currently not available
-// in some environments we build in. Reenable when that environment supports
-// this.
-#if defined(__GLIBCXX__)
-#define PERFETTO_IS_TRIVIALLY_COPYABLE(T) true
-#else
-#define PERFETTO_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
-#endif
-
 #if defined(__GNUC__) || defined(__clang__)
 #define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
diff --git a/include/perfetto/protozero/proto_decoder.h b/include/perfetto/protozero/proto_decoder.h
index 5794cc9..b58e64e 100644
--- a/include/perfetto/protozero/proto_decoder.h
+++ b/include/perfetto/protozero/proto_decoder.h
@@ -332,7 +332,7 @@
     // implicit initializers on all the ~1000 entries. We need it to initialize
     // only on the first |max_field_id| fields, the remaining capacity doesn't
     // require initialization.
-    static_assert(PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(Field) &&
+    static_assert(std::is_trivially_constructible<Field>::value &&
                       std::is_trivially_destructible<Field>::value &&
                       std::is_trivial<Field>::value,
                   "Field must be a trivial aggregate type");
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 5cd950a..5b5d5b7 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -3049,7 +3049,7 @@
     ROOT_JNI_MONITOR = 14;
   };
   // Objects retained by this root.
-  repeated uint64 object_ids = 1;
+  repeated uint64 object_ids = 1 [packed = true];
 
   optional Type root_type = 2;
 }
@@ -3065,10 +3065,10 @@
 
   // Indices for InternedData.field_names for the name of the field referring
   // to the object.
-  repeated uint64 reference_field_id = 4;
+  repeated uint64 reference_field_id = 4 [packed = true];
 
   // Ids of the Object that is referred to.
-  repeated uint64 reference_object_id = 5;
+  repeated uint64 reference_object_id = 5 [packed = true];
 }
 
 message HeapGraph {
diff --git a/protos/perfetto/trace/profiling/heap_graph.proto b/protos/perfetto/trace/profiling/heap_graph.proto
index d29c292..7e2d5d4 100644
--- a/protos/perfetto/trace/profiling/heap_graph.proto
+++ b/protos/perfetto/trace/profiling/heap_graph.proto
@@ -43,7 +43,7 @@
     ROOT_JNI_MONITOR = 14;
   };
   // Objects retained by this root.
-  repeated uint64 object_ids = 1;
+  repeated uint64 object_ids = 1 [packed = true];
 
   optional Type root_type = 2;
 }
@@ -59,10 +59,10 @@
 
   // Indices for InternedData.field_names for the name of the field referring
   // to the object.
-  repeated uint64 reference_field_id = 4;
+  repeated uint64 reference_field_id = 4 [packed = true];
 
   // Ids of the Object that is referred to.
-  repeated uint64 reference_object_id = 5;
+  repeated uint64 reference_object_id = 5 [packed = true];
 }
 
 message HeapGraph {
diff --git a/src/protozero/proto_decoder.cc b/src/protozero/proto_decoder.cc
index bd563fb..a5f1b95 100644
--- a/src/protozero/proto_decoder.cc
+++ b/src/protozero/proto_decoder.cc
@@ -208,7 +208,7 @@
   PERFETTO_CHECK(new_capacity > size_);
   std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
 
-  static_assert(PERFETTO_IS_TRIVIALLY_COPYABLE(Field),
+  static_assert(std::is_trivially_copyable<Field>::value,
                 "Field must be trivially copyable");
   memcpy(&new_storage[0], fields_, sizeof(Field) * size_);
 
diff --git a/src/trace_processor/importers/proto/heap_graph_module.cc b/src/trace_processor/importers/proto/heap_graph_module.cc
index 50bba45..7216d90 100644
--- a/src/trace_processor/importers/proto/heap_graph_module.cc
+++ b/src/trace_processor/importers/proto/heap_graph_module.cc
@@ -65,6 +65,28 @@
   }
 }
 
+// Iterate over a repeated field of varints, independent of whether it is
+// packed or not.
+template <int32_t field_no, typename T, typename F>
+bool ForEachVarInt(const T& decoder, F fn) {
+  auto field = decoder.template at<field_no>();
+  bool parse_error = false;
+  if (field.type() == protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+    // packed repeated
+    auto it = decoder.template GetPackedRepeated<
+        ::protozero::proto_utils::ProtoWireType::kVarInt, uint64_t>(
+        field_no, &parse_error);
+    for (; it; ++it)
+      fn(*it);
+  } else {
+    // non-packed repeated
+    auto it = decoder.template GetRepeated<uint64_t>(field_no);
+    for (; it; ++it)
+      fn(*it);
+  }
+  return parse_error;
+}
+
 }  // namespace
 
 void HeapGraphModule::ParseHeapGraph(int64_t ts, protozero::ConstBytes blob) {
@@ -78,21 +100,37 @@
     obj.object_id = object.id();
     obj.self_size = object.self_size();
     obj.type_id = object.type_id();
-    auto ref_field_ids_it = object.reference_field_id();
-    auto ref_object_ids_it = object.reference_object_id();
-    for (; ref_field_ids_it && ref_object_ids_it;
-         ++ref_field_ids_it, ++ref_object_ids_it) {
-      HeapGraphTracker::SourceObject::Reference ref;
-      ref.field_name_id = *ref_field_ids_it;
-      ref.owned_object_id = *ref_object_ids_it;
-      obj.references.emplace_back(std::move(ref));
+
+    std::vector<uint64_t> field_ids;
+    std::vector<uint64_t> object_ids;
+
+    bool parse_error = ForEachVarInt<
+        protos::pbzero::HeapGraphObject::kReferenceFieldIdFieldNumber>(
+        object, [&field_ids](uint64_t value) { field_ids.push_back(value); });
+
+    if (!parse_error) {
+      parse_error = ForEachVarInt<
+          protos::pbzero::HeapGraphObject::kReferenceObjectIdFieldNumber>(
+          object,
+          [&object_ids](uint64_t value) { object_ids.push_back(value); });
     }
 
-    if (ref_field_ids_it || ref_object_ids_it) {
-      context_->storage->IncrementIndexedStats(stats::heap_graph_missing_packet,
-                                               static_cast<int>(upid));
+    if (parse_error) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
+      break;
+    }
+    if (field_ids.size() != object_ids.size()) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
       continue;
     }
+    for (size_t i = 0; i < field_ids.size(); ++i) {
+      HeapGraphTracker::SourceObject::Reference ref;
+      ref.field_name_id = field_ids[i];
+      ref.owned_object_id = object_ids[i];
+      obj.references.emplace_back(std::move(ref));
+    }
     context_->heap_graph_tracker->AddObject(upid, ts, std::move(obj));
   }
   for (auto it = heap_graph.type_names(); it; ++it) {
@@ -118,8 +156,16 @@
 
     HeapGraphTracker::SourceRoot src_root;
     src_root.root_type = context_->storage->InternString(str_view);
-    for (auto obj_it = entry.object_ids(); obj_it; ++obj_it)
-      src_root.object_ids.emplace_back(*obj_it);
+    bool parse_error =
+        ForEachVarInt<protos::pbzero::HeapGraphRoot::kObjectIdsFieldNumber>(
+            entry, [&src_root](uint64_t value) {
+              src_root.object_ids.emplace_back(value);
+            });
+    if (parse_error) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
+      break;
+    }
     context_->heap_graph_tracker->AddRoot(upid, ts, std::move(src_root));
   }
   if (!heap_graph.continued()) {
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 14afab1..e93578c 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -212,7 +212,12 @@
     } else {
       auto args = proc.cmdline();
       base::StringView argv0 = args ? *args : base::StringView();
-      context_->process_tracker->SetProcessMetadata(pid, ppid, argv0);
+      UniquePid upid =
+          context_->process_tracker->SetProcessMetadata(pid, ppid, argv0);
+      if (proc.has_uid()) {
+        context_->process_tracker->SetProcessUid(
+            upid, static_cast<uint32_t>(proc.uid()));
+      }
     }
   }
 
diff --git a/src/trace_processor/process_table.cc b/src/trace_processor/process_table.cc
index adc9d1e..65d29f9 100644
--- a/src/trace_processor/process_table.cc
+++ b/src/trace_processor/process_table.cc
@@ -47,6 +47,7 @@
           SqliteTable::Column(Column::kEndTs, "end_ts", SqlValue::Type::kLong),
           SqliteTable::Column(Column::kParentUpid, "parent_upid",
                               SqlValue::Type::kLong),
+          SqliteTable::Column(Column::kUid, "uid", SqlValue::Type::kLong),
       },
       {Column::kUpid});
   return util::OkStatus();
@@ -147,6 +148,14 @@
       }
       break;
     }
+    case Column::kUid: {
+      if (process.uid.has_value()) {
+        sqlite3_result_int64(context, process.uid.value());
+      } else {
+        sqlite3_result_null(context);
+      }
+      break;
+    }
     default:
       PERFETTO_FATAL("Unknown column %d", N);
       break;
diff --git a/src/trace_processor/process_table.h b/src/trace_processor/process_table.h
index c4c1ed5..74b0386 100644
--- a/src/trace_processor/process_table.h
+++ b/src/trace_processor/process_table.h
@@ -36,7 +36,8 @@
     kPid = 2,
     kStartTs = 3,
     kEndTs = 4,
-    kParentUpid = 5
+    kParentUpid = 5,
+    kUid = 6
   };
   class Cursor : public SqliteTable::Cursor {
    public:
diff --git a/src/trace_processor/process_tracker.cc b/src/trace_processor/process_tracker.cc
index e9c0335..1ccc4b7 100644
--- a/src/trace_processor/process_tracker.cc
+++ b/src/trace_processor/process_tracker.cc
@@ -194,6 +194,10 @@
   return upid;
 }
 
+void ProcessTracker::SetProcessUid(UniquePid upid, uint32_t uid) {
+  context_->storage->GetMutableProcess(upid)->uid = uid;
+}
+
 void ProcessTracker::SetProcessNameIfUnset(UniquePid upid,
                                            StringId process_name_id) {
   TraceStorage::Process* process = context_->storage->GetMutableProcess(upid);
diff --git a/src/trace_processor/process_tracker.h b/src/trace_processor/process_tracker.h
index 7c7ea55..985212b 100644
--- a/src/trace_processor/process_tracker.h
+++ b/src/trace_processor/process_tracker.h
@@ -91,6 +91,9 @@
                                        base::Optional<uint32_t> ppid,
                                        base::StringView name);
 
+  // Sets the process user id.
+  void SetProcessUid(UniquePid upid, uint32_t uid);
+
   // Assigns the given name to the process identified by |upid| if it does not
   // have a name yet.
   void SetProcessNameIfUnset(UniquePid upid, StringId process_name_id);
diff --git a/src/trace_processor/span_join_operator_table.cc b/src/trace_processor/span_join_operator_table.cc
index 94c8ac1..24077d7 100644
--- a/src/trace_processor/span_join_operator_table.cc
+++ b/src/trace_processor/span_join_operator_table.cc
@@ -193,8 +193,7 @@
       continue;
 
     if (col_name == kTsColumnName || col_name == kDurColumnName) {
-      // We don't support constraints on ts or duration in the child tables.
-      PERFETTO_DFATAL("ts or duration constraints on child tables");
+      // Allow SQLite handle any constraints on ts or duration.
       continue;
     }
     auto op = sqlite_utils::OpToString(cs.op);
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 7243b42..2d40985 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -115,6 +115,7 @@
     StringId name_id = 0;
     uint32_t pid = 0;
     base::Optional<UniquePid> parent_upid;
+    base::Optional<uint32_t> uid;
   };
 
   // Information about a unique thread seen in a trace.
diff --git a/test/synth_common.py b/test/synth_common.py
index 3383b81..142e76e 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -173,11 +173,13 @@
     if ts is not None:
       self.packet.timestamp = ts
 
-  def add_process(self, pid, ppid, cmdline):
+  def add_process(self, pid, ppid, cmdline, uid=None):
     process = self.packet.process_tree.processes.add()
     process.pid = pid
     process.ppid = ppid
     process.cmdline.append(cmdline)
+    if uid is not None:
+      process.uid = uid
     self.proc_map[pid] = cmdline
 
   def add_thread(self, tid, tgid, cmdline):
diff --git a/test/trace_processor/index b/test/trace_processor/index
index 958b11e..808b2cf 100644
--- a/test/trace_processor/index
+++ b/test/trace_processor/index
@@ -12,6 +12,7 @@
 
 # Test for the process<>thread tracking logic.
 synth_process_tracking.py process_tracking.sql process_tracking.out
+synth_process_tracking.py process_tracking_uid.sql process_tracking_uid.out
 process_tracking_short_lived_1.py process_tracking.sql process_tracking_process_tracking_short_lived_1.out
 process_tracking_short_lived_2.py process_tracking.sql process_tracking_process_tracking_short_lived_2.out
 process_tracking_exec.py process_tracking.sql process_tracking_process_tracking_exec.out
diff --git a/test/trace_processor/process_tracking_uid.out b/test/trace_processor/process_tracking_uid.out
new file mode 100644
index 0000000..ae90e8d
--- /dev/null
+++ b/test/trace_processor/process_tracking_uid.out
@@ -0,0 +1,6 @@
+"pid","uid"
+0,"[NULL]"
+10,1001
+20,1002
+30,"[NULL]"
+40,"[NULL]"
diff --git a/test/trace_processor/process_tracking_uid.sql b/test/trace_processor/process_tracking_uid.sql
new file mode 100644
index 0000000..de06399
--- /dev/null
+++ b/test/trace_processor/process_tracking_uid.sql
@@ -0,0 +1,3 @@
+select pid, uid
+from process
+order by pid;
diff --git a/test/trace_processor/synth_process_tracking.py b/test/trace_processor/synth_process_tracking.py
index 6686d89..a7a4d2d 100644
--- a/test/trace_processor/synth_process_tracking.py
+++ b/test/trace_processor/synth_process_tracking.py
@@ -40,7 +40,7 @@
 # SQL level we should be able to tell that p1-t0 and p1-t2 belong to 'process1'
 # but p1-t1 should be left unjoinable.
 trace.add_process_tree_packet(ts=5)
-trace.add_process(10, 0, "process1")
+trace.add_process(10, 0, "process1", 1001)
 trace.add_thread(12, 10, "p1-t2")
 
 # Now create another process (pid=20) with three threads(tids=20,21,22).
@@ -58,7 +58,7 @@
 
 # From the process tracker viewpoint we pretend we only scraped tids=20,21.
 trace.add_process_tree_packet(ts=15)
-trace.add_process(20, 0, "process_2")
+trace.add_process(20, 0, "process_2", 1002)
 trace.add_thread(21, 20, "p2-t1")
 
 # Finally the very complex case: a third process (pid=30) which spawns threads