Add new table for heap_graph_class.

Bug: 150546312
Change-Id: I19d1983327882f0f07dc9ca346564535637d9f15
diff --git a/src/trace_processor/importers/proto/heap_graph_module.cc b/src/trace_processor/importers/proto/heap_graph_module.cc
index d3974ef..3ca232a 100644
--- a/src/trace_processor/importers/proto/heap_graph_module.cc
+++ b/src/trace_processor/importers/proto/heap_graph_module.cc
@@ -229,7 +229,7 @@
       PERFETTO_DLOG("Class string %s not found",
                     cls.obfuscated_name().ToStdString().c_str());
     } else {
-      const std::vector<int64_t>* cls_objects =
+      const std::vector<tables::HeapGraphClassTable::Id>* cls_objects =
           heap_graph_tracker->RowsForType(*obfuscated_class_name_id);
 
       if (cls_objects) {
@@ -237,14 +237,18 @@
             *obfuscated_class_name_id,
             context_->storage->InternString(
                 base::StringView(cls.deobfuscated_name())));
-        for (int64_t row : *cls_objects) {
+
+        for (tables::HeapGraphClassTable::Id id : *cls_objects) {
+          uint32_t row =
+              *context_->storage->heap_graph_class_table().id().IndexOf(id);
           const StringPool::Id obfuscated_type_name =
-              context_->storage->mutable_heap_graph_object_table()
-                  ->type_name()[static_cast<uint32_t>(row)];
-          context_->storage->mutable_heap_graph_object_table()
-              ->mutable_deobfuscated_type_name()
-              ->Set(static_cast<uint32_t>(row),
-                    heap_graph_tracker->MaybeDeobfuscate(obfuscated_type_name));
+              context_->storage->heap_graph_class_table().name()[row];
+          StringPool::Id deobfuscated_type_name =
+              heap_graph_tracker->MaybeDeobfuscate(obfuscated_type_name);
+          PERFETTO_CHECK(!deobfuscated_type_name.is_null());
+          context_->storage->mutable_heap_graph_class_table()
+              ->mutable_deobfuscated_name()
+              ->Set(row, deobfuscated_type_name);
         }
       } else {
         PERFETTO_DLOG("Class %s not found",
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index 2a429cd..9b370e2 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -187,31 +187,60 @@
 
 void HeapGraphTracker::FinalizeProfile(uint32_t seq_id) {
   SequenceState& sequence_state = GetOrCreateSequence(seq_id);
+
+  std::map<uint64_t, tables::HeapGraphClassTable::Id> type_id_to_db;
+  for (const auto& p : sequence_state.interned_types) {
+    uint64_t id = p.first;
+    const InternedType& interned_type = p.second;
+    base::Optional<StringPool::Id> location_name;
+    if (interned_type.location_id) {
+      auto it = sequence_state.interned_location_names.find(
+          *interned_type.location_id);
+      if (it == sequence_state.interned_location_names.end()) {
+        context_->storage->IncrementIndexedStats(
+            stats::heap_graph_invalid_string_id,
+            static_cast<int>(sequence_state.current_upid));
+
+      } else {
+        location_name = it->second;
+      }
+    }
+    auto id_and_row =
+        context_->storage->mutable_heap_graph_class_table()->Insert(
+            {interned_type.name, base::nullopt, location_name});
+
+    type_id_to_db[id] = id_and_row.id;
+    base::StringView normalized_type =
+        NormalizeTypeName(context_->storage->GetString(interned_type.name));
+    class_to_rows_[context_->storage->InternString(normalized_type)]
+        .emplace_back(id_and_row.id);
+  }
+
   for (const SourceObject& obj : sequence_state.current_objects) {
-    auto it = sequence_state.interned_types.find(obj.type_id);
-    if (it == sequence_state.interned_types.end()) {
+    auto type_it = type_id_to_db.find(obj.type_id);
+    if (type_it == type_id_to_db.end()) {
       context_->storage->IncrementIndexedStats(
-          stats::heap_graph_invalid_string_id,
+          stats::heap_graph_malformed_packet,
           static_cast<int>(sequence_state.current_upid));
       continue;
     }
-    const InternedType& interned_type = it->second;
-    StringPool::Id type_name = interned_type.name;
-    context_->storage->mutable_heap_graph_object_table()->Insert(
-        {sequence_state.current_upid, sequence_state.current_ts,
-         static_cast<int64_t>(obj.object_id),
-         static_cast<int64_t>(obj.self_size), /*retained_size=*/-1,
-         /*unique_retained_size=*/-1, /*reference_set_id=*/base::nullopt,
-         /*reachable=*/0, /*type_name=*/type_name,
-         /*deobfuscated_type_name=*/base::nullopt,
-         /*root_type=*/base::nullopt});
-    int64_t row = context_->storage->heap_graph_object_table().row_count() - 1;
+    tables::HeapGraphClassTable::Id db_id = type_it->second;
+    auto id_and_row =
+        context_->storage->mutable_heap_graph_object_table()->Insert(
+            {sequence_state.current_upid, sequence_state.current_ts,
+             static_cast<int64_t>(obj.object_id),
+             static_cast<int64_t>(obj.self_size), /*retained_size=*/-1,
+             /*unique_retained_size=*/-1, /*reference_set_id=*/base::nullopt,
+             /*reachable=*/0, db_id,
+             /*root_type=*/base::nullopt});
+    int64_t row = id_and_row.row;
     sequence_state.object_id_to_row.emplace(obj.object_id, row);
-    base::StringView normalized_type =
-        NormalizeTypeName(context_->storage->GetString(type_name));
-    class_to_rows_[context_->storage->InternString(normalized_type)]
-        .emplace_back(row);
-    sequence_state.walker.AddNode(row, obj.self_size, type_name.raw_id());
+    int64_t type_row =
+        *context_->storage->heap_graph_class_table().id().IndexOf(db_id);
+    // Still using raw rows for the HeapGraphWalker to not tie it to the
+    // data base and make it useable independently.
+    // We will eventually want to use that client-side for summarization.
+    sequence_state.walker.AddNode(row, obj.self_size, type_row);
   }
 
   for (const SourceObject& obj : sequence_state.current_objects) {
@@ -323,12 +352,21 @@
       parent_id = node_to_id[node.parent_id];
     const uint32_t depth = node.depth;
 
+    base::Optional<StringPool::Id> name =
+        context_->storage->heap_graph_class_table()
+            .deobfuscated_name()[static_cast<uint32_t>(node.class_name)];
+    if (!name) {
+      name = context_->storage->heap_graph_class_table()
+                 .name()[static_cast<uint32_t>(node.class_name)];
+    }
+    PERFETTO_CHECK(name);
+
     tables::ExperimentalFlamegraphNodesTable::Row alloc_row{};
     alloc_row.ts = current_ts;
     alloc_row.upid = current_upid;
     alloc_row.profile_type = profile_type;
     alloc_row.depth = depth;
-    alloc_row.name = MaybeDeobfuscate(StringId::Raw(node.class_name));
+    alloc_row.name = *name;
     alloc_row.map_name = java_mapping;
     alloc_row.count = static_cast<int64_t>(node.count);
     alloc_row.cumulative_count =
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.h b/src/trace_processor/importers/proto/heap_graph_tracker.h
index e68209b..6623235 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.h
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/string_view.h"
 
 #include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
 #include "src/trace_processor/importers/proto/heap_graph_walker.h"
@@ -103,7 +104,8 @@
                                StringPool::Id deobfuscated_name);
   StringPool::Id MaybeDeobfuscate(StringPool::Id);
 
-  const std::vector<int64_t>* RowsForType(StringPool::Id type_name) const {
+  const std::vector<tables::HeapGraphClassTable::Id>* RowsForType(
+      StringPool::Id type_name) const {
     auto it = class_to_rows_.find(type_name);
     if (it == class_to_rows_.end())
       return nullptr;
@@ -152,7 +154,8 @@
   std::map<uint32_t, SequenceState> sequence_state_;
   std::map<std::pair<UniquePid, int64_t /* ts */>, HeapGraphWalker> walkers_;
 
-  std::map<StringPool::Id, std::vector<int64_t>> class_to_rows_;
+  std::map<StringPool::Id, std::vector<tables::HeapGraphClassTable::Id>>
+      class_to_rows_;
   std::map<StringPool::Id, std::vector<int64_t>> field_to_rows_;
 
   std::map<StringPool::Id, StringPool::Id> deobfuscation_mapping_;
diff --git a/src/trace_processor/importers/proto/heap_graph_walker.cc b/src/trace_processor/importers/proto/heap_graph_walker.cc
index fc9e415..0082a3f 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_walker.cc
@@ -59,7 +59,9 @@
 
 HeapGraphWalker::Delegate::~Delegate() = default;
 
-void HeapGraphWalker::AddNode(int64_t row, uint64_t size, uint32_t class_name) {
+void HeapGraphWalker::AddNode(int64_t row,
+                              uint64_t size,
+                              ClassNameId class_name) {
   if (static_cast<size_t>(row) >= nodes_.size())
     nodes_.resize(static_cast<size_t>(row) + 1);
   Node& node = GetNode(row);
diff --git a/src/trace_processor/importers/proto/heap_graph_walker.h b/src/trace_processor/importers/proto/heap_graph_walker.h
index e034f1a..128aa57 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker.h
+++ b/src/trace_processor/importers/proto/heap_graph_walker.h
@@ -97,7 +97,7 @@
 
 class HeapGraphWalker {
  public:
-  using ClassNameId = uint32_t;
+  using ClassNameId = int64_t;
 
   struct PathFromRoot {
     static constexpr size_t kRoot = 0;
@@ -149,7 +149,7 @@
     uint64_t lowlink = 0;
     int64_t component = -1;
 
-    uint32_t class_name = 0;
+    ClassNameId class_name = 0;
     int32_t distance_to_root = -1;
 
     bool on_stack = false;
diff --git a/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc b/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
index 322fd5a..3a55dda 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
+++ b/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
@@ -596,7 +596,7 @@
 }
 
 bool HasPath(const HeapGraphWalker::PathFromRoot& path,
-             std::vector<uint32_t> class_names) {
+             std::vector<HeapGraphWalker::ClassNameId> class_names) {
   return HasPath(path, path.nodes[HeapGraphWalker::PathFromRoot::kRoot],
                  std::move(class_names));
 }
diff --git a/src/trace_processor/metrics/android/java_heap_histogram.sql b/src/trace_processor/metrics/android/java_heap_histogram.sql
index b6832c0..a8d9b5f 100644
--- a/src/trace_processor/metrics/android/java_heap_histogram.sql
+++ b/src/trace_processor/metrics/android/java_heap_histogram.sql
@@ -21,12 +21,12 @@
 -- Base histogram table
 heap_obj_histograms AS (
   SELECT
-    upid,
-    graph_sample_ts,
-    IFNULL(deobfuscated_type_name, type_name) AS type_name,
+    o.upid,
+    o.graph_sample_ts,
+    IFNULL(c.deobfuscated_name, c.name) AS type_name,
     COUNT(1) obj_count,
-    SUM(CASE reachable WHEN TRUE THEN 1 ELSE 0 END) reachable_obj_count
-  FROM heap_graph_object
+    SUM(CASE o.reachable WHEN TRUE THEN 1 ELSE 0 END) reachable_obj_count
+  FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id
   GROUP BY 1, 2, 3
 ),
 -- Group by to build the repeated field by upid, ts
diff --git a/src/trace_processor/metrics/android/unmapped_java_symbols.sql b/src/trace_processor/metrics/android/unmapped_java_symbols.sql
index 0fc8443..1b7f829 100644
--- a/src/trace_processor/metrics/android/unmapped_java_symbols.sql
+++ b/src/trace_processor/metrics/android/unmapped_java_symbols.sql
@@ -22,9 +22,9 @@
   FROM (
     SELECT
       upid,
-      RTRIM(REPLACE(type_name, 'java.lang.Class<', ''), '[]>') AS type_name
-    FROM heap_graph_object
-    WHERE deobfuscated_type_name IS NULL
+      RTRIM(REPLACE(c.name, 'java.lang.Class<', ''), '[]>') AS type_name
+    FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id
+    WHERE c.deobfuscated_name IS NULL
   )
   WHERE type_name NOT IN ('byte', 'char', 'short', 'int', 'long', 'boolean', 'float', 'double')
   AND type_name NOT LIKE '$Proxy%'
@@ -43,9 +43,10 @@
 
 CREATE TABLE IF NOT EXISTS fields_per_upid AS
 WITH distinct_unmapped_field_names AS (
-  SELECT DISTINCT upid, field_type_name, field_name
-  FROM heap_graph_object JOIN heap_graph_reference USING (reference_set_id)
-  WHERE deobfuscated_type_name IS NULL
+  SELECT DISTINCT o.upid, field_type_name, field_name
+    FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id
+           JOIN heap_graph_reference USING (reference_set_id)
+  WHERE c.deobfuscated_name IS NULL
   AND field_name NOT LIKE '$Proxy%'
   AND field_name NOT LIKE 'java.%'
   AND field_name NOT LIKE 'javax.%'
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 733a780..95d6d94 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -534,6 +534,13 @@
   tables::HeapGraphObjectTable* mutable_heap_graph_object_table() {
     return &heap_graph_object_table_;
   }
+  const tables::HeapGraphClassTable& heap_graph_class_table() const {
+    return heap_graph_class_table_;
+  }
+
+  tables::HeapGraphClassTable* mutable_heap_graph_class_table() {
+    return &heap_graph_class_table_;
+  }
 
   const tables::HeapGraphReferenceTable& heap_graph_reference_table() const {
     return heap_graph_reference_table_;
@@ -772,6 +779,7 @@
   // Symbol tables (mappings from frames to symbol names)
   tables::SymbolTable symbol_table_{&string_pool_, nullptr};
   tables::HeapGraphObjectTable heap_graph_object_table_{&string_pool_, nullptr};
+  tables::HeapGraphClassTable heap_graph_class_table_{&string_pool_, nullptr};
   tables::HeapGraphReferenceTable heap_graph_reference_table_{&string_pool_,
                                                               nullptr};
 
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index b58c908..e4d6ba5 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -118,19 +118,27 @@
 
 PERFETTO_TP_TABLE(PERFETTO_TP_EXPERIMENTAL_FLAMEGRAPH_NODES);
 
-#define PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF(NAME, PARENT, C)  \
-  NAME(HeapGraphObjectTable, "heap_graph_object")           \
-  PERFETTO_TP_ROOT_TABLE(PARENT, C)                         \
-  C(uint32_t, upid)                                         \
-  C(int64_t, graph_sample_ts)                               \
-  C(int64_t, object_id)                                     \
-  C(int64_t, self_size)                                     \
-  C(int64_t, retained_size)                                 \
-  C(int64_t, unique_retained_size)                          \
-  C(base::Optional<uint32_t>, reference_set_id)             \
-  C(int32_t, reachable)                                     \
-  C(StringPool::Id, type_name)                              \
-  C(base::Optional<StringPool::Id>, deobfuscated_type_name) \
+#define PERFETTO_TP_HEAP_GRAPH_CLASS_DEF(NAME, PARENT, C) \
+  NAME(HeapGraphClassTable, "heap_graph_class")           \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                       \
+  C(StringPool::Id, name)                                 \
+  C(base::Optional<StringPool::Id>, deobfuscated_name)    \
+  C(base::Optional<StringPool::Id>, location)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_CLASS_DEF);
+
+#define PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF(NAME, PARENT, C) \
+  NAME(HeapGraphObjectTable, "heap_graph_object")          \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                        \
+  C(uint32_t, upid)                                        \
+  C(int64_t, graph_sample_ts)                              \
+  C(int64_t, object_id)                                    \
+  C(int64_t, self_size)                                    \
+  C(int64_t, retained_size)                                \
+  C(int64_t, unique_retained_size)                         \
+  C(base::Optional<uint32_t>, reference_set_id)            \
+  C(int32_t, reachable)                                    \
+  C(HeapGraphClassTable::Id, type_id)                      \
   C(base::Optional<StringPool::Id>, root_type)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF);
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 8e6dd44..50953fb 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -51,6 +51,7 @@
 HeapProfileAllocationTable::~HeapProfileAllocationTable() = default;
 ExperimentalFlamegraphNodesTable::~ExperimentalFlamegraphNodesTable() = default;
 HeapGraphObjectTable::~HeapGraphObjectTable() = default;
+HeapGraphClassTable::~HeapGraphClassTable() = default;
 HeapGraphReferenceTable::~HeapGraphReferenceTable() = default;
 VulkanMemoryAllocationsTable::~VulkanMemoryAllocationsTable() = default;
 PackageListTable::~PackageListTable() = default;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index e90f50d..c44a56c 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -528,6 +528,7 @@
 
   RegisterDbTable(storage->heap_graph_object_table());
   RegisterDbTable(storage->heap_graph_reference_table());
+  RegisterDbTable(storage->heap_graph_class_table());
 
   RegisterDbTable(storage->symbol_table());
   RegisterDbTable(storage->heap_profile_allocation_table());
diff --git a/test/trace_processor/heap_graph_object.sql b/test/trace_processor/heap_graph_object.sql
index 234728f..d84ea66 100644
--- a/test/trace_processor/heap_graph_object.sql
+++ b/test/trace_processor/heap_graph_object.sql
@@ -13,4 +13,17 @@
 -- See the License for the specific language governing permissions and
 -- limitations under the License.
 --
-select * from heap_graph_object
+select o.id,
+       o.type,
+       o.upid,
+       o.graph_sample_ts,
+       o.object_id,
+       o.self_size,
+       o.retained_size,
+       o.unique_retained_size,
+       o.reference_set_id,
+       o.reachable,
+       c.name as type_name,
+       c.deobfuscated_name as deobfuscated_type_name,
+       o.root_type
+from heap_graph_object o join heap_graph_class c on o.type_id = c.id