Create proper table for packages list.

Bug: 150546312
Change-Id: Ib22ac967c075db95d661f44c2291554a3befccea
diff --git a/Android.bp b/Android.bp
index 53c1ddc..e3d4697 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6527,6 +6527,7 @@
     "src/trace_processor/importers/json/json_tracker.cc",
     "src/trace_processor/importers/proto/android_probes_module.cc",
     "src/trace_processor/importers/proto/android_probes_parser.cc",
+    "src/trace_processor/importers/proto/android_probes_tracker.cc",
     "src/trace_processor/importers/proto/graphics_event_module.cc",
     "src/trace_processor/importers/proto/graphics_event_parser.cc",
     "src/trace_processor/importers/proto/heap_graph_module.cc",
diff --git a/BUILD b/BUILD
index 922f2f0..a50a6fd 100644
--- a/BUILD
+++ b/BUILD
@@ -923,6 +923,8 @@
         "src/trace_processor/importers/proto/android_probes_module.h",
         "src/trace_processor/importers/proto/android_probes_parser.cc",
         "src/trace_processor/importers/proto/android_probes_parser.h",
+        "src/trace_processor/importers/proto/android_probes_tracker.cc",
+        "src/trace_processor/importers/proto/android_probes_tracker.h",
         "src/trace_processor/importers/proto/graphics_event_module.cc",
         "src/trace_processor/importers/proto/graphics_event_module.h",
         "src/trace_processor/importers/proto/graphics_event_parser.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 51f93d7..6138ab6 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -226,6 +226,8 @@
     "importers/proto/android_probes_module.h",
     "importers/proto/android_probes_parser.cc",
     "importers/proto/android_probes_parser.h",
+    "importers/proto/android_probes_tracker.cc",
+    "importers/proto/android_probes_tracker.h",
     "importers/proto/graphics_event_module.cc",
     "importers/proto/graphics_event_module.h",
     "importers/proto/graphics_event_parser.cc",
diff --git a/src/trace_processor/importers/proto/android_probes_parser.cc b/src/trace_processor/importers/proto/android_probes_parser.cc
index 1952fef..1f19644 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.cc
+++ b/src/trace_processor/importers/proto/android_probes_parser.cc
@@ -38,6 +38,8 @@
 #include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
 #include "protos/perfetto/trace/system_info.pbzero.h"
 
+#include "src/trace_processor/importers/proto/android_probes_tracker.h"
+
 namespace perfetto {
 namespace trace_processor {
 
@@ -221,26 +223,19 @@
   context_->storage->SetStats(stats::packages_list_has_parse_errors,
                               pkg_list.parse_error());
 
-  // Insert the package info into arg sets (one set per package), with the arg
-  // set ids collected in the Metadata table, under
-  // metadata::android_packages_list key type.
+  AndroidProbesTracker* tracker = AndroidProbesTracker::GetOrCreate(context_);
   for (auto it = pkg_list.packages(); it; ++it) {
-    // Insert a placeholder metadata entry, which will be overwritten by the
-    // arg_set_id when the arg tracker is flushed.
-    auto id = context_->metadata_tracker->AppendMetadata(
-        metadata::android_packages_list, Variadic::Integer(0));
-    auto add_arg = [this, id](base::StringView name, Variadic value) {
-      StringId key_id = context_->storage->InternString(name);
-      context_->args_tracker->AddArgsTo(id).AddArg(key_id, value);
-    };
     protos::pbzero::PackagesList_PackageInfo::Decoder pkg(*it);
-    add_arg("name",
-            Variadic::String(context_->storage->InternString(pkg.name())));
-    add_arg("uid", Variadic::UnsignedInteger(pkg.uid()));
-    add_arg("debuggable", Variadic::Boolean(pkg.debuggable()));
-    add_arg("profileable_from_shell",
-            Variadic::Boolean(pkg.profileable_from_shell()));
-    add_arg("version_code", Variadic::Integer(pkg.version_code()));
+    std::string pkg_name = pkg.name().ToStdString();
+    if (!tracker->ShouldInsertPackage(pkg_name)) {
+      continue;
+    }
+    context_->storage->mutable_package_list_table()->Insert(
+        {context_->storage->InternString(pkg.name()),
+         static_cast<int64_t>(pkg.uid()), pkg.debuggable(),
+         pkg.profileable_from_shell(),
+         static_cast<int64_t>(pkg.version_code())});
+    tracker->InsertedPackage(std::move(pkg_name));
   }
 }
 
diff --git a/src/trace_processor/importers/proto/android_probes_tracker.cc b/src/trace_processor/importers/proto/android_probes_tracker.cc
new file mode 100644
index 0000000..490ac87
--- /dev/null
+++ b/src/trace_processor/importers/proto/android_probes_tracker.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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/trace_processor/importers/proto/android_probes_tracker.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+AndroidProbesTracker::AndroidProbesTracker(TraceProcessorContext*) {}
+
+AndroidProbesTracker::~AndroidProbesTracker() = default;
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/android_probes_tracker.h b/src/trace_processor/importers/proto/android_probes_tracker.h
new file mode 100644
index 0000000..f50fd81
--- /dev/null
+++ b/src/trace_processor/importers/proto/android_probes_tracker.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 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_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_PROBES_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_PROBES_TRACKER_H_
+
+#include <set>
+
+#include "perfetto/ext/base/optional.h"
+
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class AndroidProbesTracker : public Destructible {
+ public:
+  explicit AndroidProbesTracker(TraceProcessorContext*);
+  ~AndroidProbesTracker() override;
+
+  static AndroidProbesTracker* GetOrCreate(TraceProcessorContext* context) {
+    if (!context->android_probes_tracker) {
+      context->android_probes_tracker.reset(new AndroidProbesTracker(context));
+    }
+    return static_cast<AndroidProbesTracker*>(
+        context->android_probes_tracker.get());
+  }
+
+  bool ShouldInsertPackage(const std::string& package_name) const {
+    auto it = seen_packages_.find(package_name);
+    return it == seen_packages_.end();
+  }
+
+  void InsertedPackage(std::string package_name) {
+    seen_packages_.emplace(std::move(package_name));
+  }
+
+ private:
+  std::set<std::string> seen_packages_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_PROBES_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 338e58d..e166e45 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -2462,41 +2462,67 @@
   // The relevant arg sets have the info about the packages. To simplify test
   // structure, make an assumption that metadata storage is filled in in the
   // FIFO order of seen packages.
-  const auto& args = context_.storage->arg_table();
-  const auto& metadata = context_.storage->metadata_table();
-
-  Table package_list = metadata.Filter(
-      {metadata.name().eq(metadata::kNames[metadata::android_packages_list])});
+  const auto& package_list = context_.storage->package_list_table();
   ASSERT_EQ(package_list.row_count(), 2u);
 
-  const Column* int_value = package_list.GetColumnByName("int_value");
-  uint32_t first_set_id = static_cast<uint32_t>(int_value->Get(0).long_value);
-  uint32_t second_set_id = static_cast<uint32_t>(int_value->Get(1).long_value);
+  EXPECT_STREQ(storage_->GetString(package_list.package_name()[0]).c_str(),
+               "com.test.app");
+  EXPECT_EQ(package_list.uid()[0], 1000u);
+  EXPECT_EQ(package_list.debuggable()[0], false);
+  EXPECT_EQ(package_list.profileable_from_shell()[0], true);
+  EXPECT_EQ(package_list.version_code()[0], 42);
 
-  // helper to look up arg values
-  auto find_arg = [&args, this](ArgSetId set_id, const char* arg_name) {
-    for (uint32_t i = 0; i < args.row_count(); i++) {
-      if (args.arg_set_id()[i] == set_id &&
-          args.key()[i] == storage_->InternString(arg_name))
-        return storage_->GetArgValue(i);
-    }
-    PERFETTO_FATAL("Didn't find expected argument");
-  };
+  EXPECT_STREQ(storage_->GetString(package_list.package_name()[1]).c_str(),
+               "com.test.app2");
+  EXPECT_EQ(package_list.uid()[1], 1001u);
+  EXPECT_EQ(package_list.debuggable()[1], false);
+  EXPECT_EQ(package_list.profileable_from_shell()[1], false);
+  EXPECT_EQ(package_list.version_code()[1], 43);
+}
 
-  auto first_name_id = find_arg(first_set_id, "name").string_value;
-  EXPECT_STREQ(storage_->GetString(first_name_id).c_str(), "com.test.app");
-  EXPECT_EQ(find_arg(first_set_id, "uid").uint_value, 1000u);
-  EXPECT_EQ(find_arg(first_set_id, "debuggable").bool_value, false);
-  EXPECT_EQ(find_arg(first_set_id, "profileable_from_shell").bool_value, true);
-  EXPECT_EQ(find_arg(first_set_id, "version_code").int_value, 42);
+TEST_F(ProtoTraceParserTest, AndroidPackagesListDuplicate) {
+  auto* packet = trace_.add_packet();
+  auto* pkg_list = packet->set_packages_list();
 
-  auto second_name_id = find_arg(second_set_id, "name").string_value;
-  EXPECT_STREQ(storage_->GetString(second_name_id).c_str(), "com.test.app2");
-  EXPECT_EQ(find_arg(second_set_id, "uid").uint_value, 1001u);
-  EXPECT_EQ(find_arg(second_set_id, "debuggable").bool_value, false);
-  EXPECT_EQ(find_arg(second_set_id, "profileable_from_shell").bool_value,
-            false);
-  EXPECT_EQ(find_arg(second_set_id, "version_code").int_value, 43);
+  pkg_list->set_read_error(false);
+  pkg_list->set_parse_error(true);
+  {
+    auto* pkg = pkg_list->add_packages();
+    pkg->set_name("com.test.app");
+    pkg->set_uid(1000);
+    pkg->set_debuggable(false);
+    pkg->set_profileable_from_shell(true);
+    pkg->set_version_code(42);
+  }
+  {
+    auto* pkg = pkg_list->add_packages();
+    pkg->set_name("com.test.app");
+    pkg->set_uid(1000);
+    pkg->set_debuggable(false);
+    pkg->set_profileable_from_shell(true);
+    pkg->set_version_code(42);
+  }
+
+  Tokenize();
+
+  // Packet-level errors reflected in stats storage.
+  const auto& stats = context_.storage->stats();
+  EXPECT_FALSE(stats[stats::packages_list_has_read_errors].value);
+  EXPECT_TRUE(stats[stats::packages_list_has_parse_errors].value);
+
+  // Expect two metadata rows, each with an int_value of a separate arg set id.
+  // The relevant arg sets have the info about the packages. To simplify test
+  // structure, make an assumption that metadata storage is filled in in the
+  // FIFO order of seen packages.
+  const auto& package_list = context_.storage->package_list_table();
+  ASSERT_EQ(package_list.row_count(), 1u);
+
+  EXPECT_STREQ(storage_->GetString(package_list.package_name()[0]).c_str(),
+               "com.test.app");
+  EXPECT_EQ(package_list.uid()[0], 1000u);
+  EXPECT_EQ(package_list.debuggable()[0], false);
+  EXPECT_EQ(package_list.profileable_from_shell()[0], true);
+  EXPECT_EQ(package_list.version_code()[0], 42);
 }
 
 TEST_F(ProtoTraceParserTest, ParseCPUProfileSamplesIntoTable) {
diff --git a/src/trace_processor/metrics/android/android_package_list.sql b/src/trace_processor/metrics/android/android_package_list.sql
index 7ca9c15..5e05281 100644
--- a/src/trace_processor/metrics/android/android_package_list.sql
+++ b/src/trace_processor/metrics/android/android_package_list.sql
@@ -14,43 +14,6 @@
 -- limitations under the License.
 --
 
--- Get distinct packages list
-DROP VIEW IF EXISTS package_arg_ids;
-
-CREATE VIEW package_arg_ids AS
-SELECT int_value AS arg_set_id
-FROM metadata WHERE name = 'android_packages_list';
-
--- Generate a table mapping package names to their attributes
-DROP VIEW IF EXISTS package_args;
-
-CREATE VIEW package_args AS
-SELECT arg_set_id, key, string_value, int_value
-FROM package_arg_ids JOIN args USING(arg_set_id);
-
-DROP TABLE IF EXISTS package_list;
-
-CREATE TABLE package_list(
-  package_name TEXT PRIMARY KEY,
-  uid INT,
-  version_code INT,
-  debuggable INT
-);
-
-INSERT OR REPLACE INTO package_list
-SELECT names.name, uids.uid, versions.version, debuggable.is_debug
-FROM
-  (SELECT arg_set_id, string_value name FROM package_args WHERE key = 'name')
-    AS names
-  JOIN (SELECT arg_set_id, int_value uid FROM package_args WHERE key = 'uid')
-    AS uids USING (arg_set_id)
-  JOIN (SELECT arg_set_id, int_value version FROM package_args WHERE key = 'version_code')
-    AS versions USING (arg_set_id)
-  JOIN (SELECT arg_set_id, int_value is_debug FROM package_args WHERE key = 'debuggable')
-    AS debuggable USING (arg_set_id);
-
-DROP VIEW IF EXISTS android_package_list_output;
-
 CREATE VIEW android_package_list_output AS
 SELECT AndroidPackageList(
   'packages', (
diff --git a/src/trace_processor/metrics/android/process_metadata.sql b/src/trace_processor/metrics/android/process_metadata.sql
index d38795f..401948d 100644
--- a/src/trace_processor/metrics/android/process_metadata.sql
+++ b/src/trace_processor/metrics/android/process_metadata.sql
@@ -14,8 +14,6 @@
 -- limitations under the License.
 --
 
-SELECT RUN_METRIC('android/android_package_list.sql');
-
 DROP TABLE IF EXISTS uid_package_count;
 
 CREATE TABLE uid_package_count AS
diff --git a/src/trace_processor/storage/metadata.h b/src/trace_processor/storage/metadata.h
index fa2643d..1663ff3 100644
--- a/src/trace_processor/storage/metadata.h
+++ b/src/trace_processor/storage/metadata.h
@@ -38,7 +38,6 @@
   F(benchmark_story_run_index,         KeyType::kSingle,  Variadic::kInt),    \
   F(benchmark_story_run_time_us,       KeyType::kSingle,  Variadic::kInt),    \
   F(benchmark_story_tags,              KeyType::kMulti,   Variadic::kString), \
-  F(android_packages_list,             KeyType::kMulti,   Variadic::kInt),    \
   F(statsd_triggering_subscription_id, KeyType::kSingle,  Variadic::kInt),    \
   F(trace_uuid,                        KeyType::kSingle,  Variadic::kString), \
   F(system_name,                       KeyType::kSingle,  Variadic::kString), \
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 53e9e12..5539579 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -508,6 +508,13 @@
     return &heap_profile_allocation_table_;
   }
 
+  const tables::PackageListTable& package_list_table() const {
+    return package_list_table_;
+  }
+  tables::PackageListTable* mutable_package_list_table() {
+    return &package_list_table_;
+  }
+
   const tables::CpuProfileStackSampleTable& cpu_profile_stack_sample_table()
       const {
     return cpu_profile_stack_sample_table_;
@@ -756,6 +763,7 @@
       &string_pool_, nullptr};
   tables::CpuProfileStackSampleTable cpu_profile_stack_sample_table_{
       &string_pool_, nullptr};
+  tables::PackageListTable package_list_table_{&string_pool_, nullptr};
 
   // Symbol tables (mappings from frames to symbol names)
   tables::SymbolTable symbol_table_{&string_pool_, nullptr};
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index e96772b..b58c908 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -23,6 +23,17 @@
 namespace trace_processor {
 namespace tables {
 
+#define PERFETTO_TP_PACKAGES_LIST_DEF(NAME, PARENT, C) \
+  NAME(PackageListTable, "package_list")               \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                    \
+  C(StringPool::Id, package_name)                      \
+  C(int64_t, uid)                                      \
+  C(int32_t, debuggable)                               \
+  C(int32_t, profileable_from_shell)                   \
+  C(int64_t, version_code)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_PACKAGES_LIST_DEF);
+
 #define PERFETTO_TP_STACK_PROFILE_MAPPING_DEF(NAME, PARENT, C) \
   NAME(StackProfileMappingTable, "stack_profile_mapping")      \
   PERFETTO_TP_ROOT_TABLE(PARENT, C)                            \
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 11e78b0..8e6dd44 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -53,6 +53,7 @@
 HeapGraphObjectTable::~HeapGraphObjectTable() = default;
 HeapGraphReferenceTable::~HeapGraphReferenceTable() = default;
 VulkanMemoryAllocationsTable::~VulkanMemoryAllocationsTable() = default;
+PackageListTable::~PackageListTable() = default;
 
 // slice_tables.h
 SliceTable::~SliceTable() = default;
diff --git a/src/trace_processor/trace_processor_context.h b/src/trace_processor/trace_processor_context.h
index 64c2cbc..1f5cd64 100644
--- a/src/trace_processor/trace_processor_context.h
+++ b/src/trace_processor/trace_processor_context.h
@@ -29,6 +29,7 @@
 namespace trace_processor {
 
 class ArgsTracker;
+class AndroidProbesTracker;
 class ChunkedTraceReader;
 class ClockTracker;
 class EventTracker;
@@ -79,11 +80,12 @@
   // type is only available in storage_full target. To access these fields use
   // the GetOrCreate() method on their subclass type, e.g.
   // SyscallTracker::GetOrCreate(context)
-  std::unique_ptr<Destructible> syscall_tracker;     // SyscallTracker
-  std::unique_ptr<Destructible> sched_tracker;       // SchedEventTracker
-  std::unique_ptr<Destructible> systrace_parser;     // SystraceParser
-  std::unique_ptr<Destructible> heap_graph_tracker;  // HeapGraphTracker
-  std::unique_ptr<Destructible> json_tracker;        // JsonTracker
+  std::unique_ptr<Destructible> android_probes_tracker;  // AndroidProbesTracker
+  std::unique_ptr<Destructible> syscall_tracker;         // SyscallTracker
+  std::unique_ptr<Destructible> sched_tracker;           // SchedEventTracker
+  std::unique_ptr<Destructible> systrace_parser;         // SystraceParser
+  std::unique_ptr<Destructible> heap_graph_tracker;      // HeapGraphTracker
+  std::unique_ptr<Destructible> json_tracker;            // JsonTracker
 
   // These fields are trace readers which will be called by |forwarding_parser|
   // once the format of the trace is discovered. They are placed here as they
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 9c24644..e90f50d 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -535,6 +535,7 @@
   RegisterDbTable(storage->stack_profile_callsite_table());
   RegisterDbTable(storage->stack_profile_mapping_table());
   RegisterDbTable(storage->stack_profile_frame_table());
+  RegisterDbTable(storage->package_list_table());
 
   RegisterDbTable(storage->android_log_table());