Use DeobfuscationMapping in TraceProcessor for translation Java class names from the "args" table.

Currently we translate only args with a flat_key = "android_view_dump.activity.view.class_name".

Bug: b/244700870
Change-Id: Ibb95f1eff3399fb7594e12c1332cd6cbf50d32a8
diff --git a/Android.bp b/Android.bp
index a0d2e95..0d5af36 100644
--- a/Android.bp
+++ b/Android.bp
@@ -9110,6 +9110,7 @@
         "src/trace_processor/importers/common/args_tracker.cc",
         "src/trace_processor/importers/common/args_translation_table.cc",
         "src/trace_processor/importers/common/clock_tracker.cc",
+        "src/trace_processor/importers/common/deobfuscation_mapping_table.cc",
         "src/trace_processor/importers/common/event_tracker.cc",
         "src/trace_processor/importers/common/flow_tracker.cc",
         "src/trace_processor/importers/common/global_args_tracker.cc",
@@ -9127,6 +9128,7 @@
     srcs: [
         "src/trace_processor/importers/common/args_translation_table_unittest.cc",
         "src/trace_processor/importers/common/clock_tracker_unittest.cc",
+        "src/trace_processor/importers/common/deobfuscation_mapping_table_unittest.cc",
         "src/trace_processor/importers/common/event_tracker_unittest.cc",
         "src/trace_processor/importers/common/flow_tracker_unittest.cc",
         "src/trace_processor/importers/common/process_tracker_unittest.cc",
diff --git a/BUILD b/BUILD
index 83e46a7..5942660 100644
--- a/BUILD
+++ b/BUILD
@@ -1111,6 +1111,8 @@
         "src/trace_processor/importers/common/chunked_trace_reader.h",
         "src/trace_processor/importers/common/clock_tracker.cc",
         "src/trace_processor/importers/common/clock_tracker.h",
+        "src/trace_processor/importers/common/deobfuscation_mapping_table.cc",
+        "src/trace_processor/importers/common/deobfuscation_mapping_table.h",
         "src/trace_processor/importers/common/event_tracker.cc",
         "src/trace_processor/importers/common/event_tracker.h",
         "src/trace_processor/importers/common/flow_tracker.cc",
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index 5d19218..eb33f16 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -23,6 +23,8 @@
     "chunked_trace_reader.h",
     "clock_tracker.cc",
     "clock_tracker.h",
+    "deobfuscation_mapping_table.cc",
+    "deobfuscation_mapping_table.h",
     "event_tracker.cc",
     "event_tracker.h",
     "flow_tracker.cc",
@@ -63,6 +65,7 @@
   sources = [
     "args_translation_table_unittest.cc",
     "clock_tracker_unittest.cc",
+    "deobfuscation_mapping_table_unittest.cc",
     "event_tracker_unittest.cc",
     "flow_tracker_unittest.cc",
     "process_tracker_unittest.cc",
diff --git a/src/trace_processor/importers/common/args_tracker.cc b/src/trace_processor/importers/common/args_tracker.cc
index 5faa718..113c590 100644
--- a/src/trace_processor/importers/common/args_tracker.cc
+++ b/src/trace_processor/importers/common/args_tracker.cc
@@ -106,10 +106,10 @@
 }
 
 bool ArgsTracker::NeedsTranslation(const ArgsTranslationTable& table) const {
-  return std::any_of(args_.begin(), args_.end(),
-                     [&table](const GlobalArgsTracker::Arg& arg) {
-                       return table.NeedsTranslation(arg.key, arg.value.type);
-                     });
+  return std::any_of(
+      args_.begin(), args_.end(), [&table](const GlobalArgsTracker::Arg& arg) {
+        return table.NeedsTranslation(arg.flat_key, arg.key, arg.value.type);
+      });
 }
 
 ArgsTracker::BoundInserter::BoundInserter(ArgsTracker* args_tracker,
diff --git a/src/trace_processor/importers/common/args_translation_table.cc b/src/trace_processor/importers/common/args_translation_table.cc
index b35f427..d1559e0 100644
--- a/src/trace_processor/importers/common/args_translation_table.cc
+++ b/src/trace_processor/importers/common/args_translation_table.cc
@@ -15,7 +15,9 @@
  */
 
 #include "src/trace_processor/importers/common/args_translation_table.h"
+#include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -90,12 +92,14 @@
           storage->InternString(kMojoMethodMappingIdKey)),
       interned_mojo_method_rel_pc_(storage->InternString(kMojoMethodRelPcKey)),
       interned_mojo_method_name_(storage->InternString(kMojoMethodNameKey)),
-      interned_mojo_interface_tag_(storage->InternString(kMojoIntefaceTagKey)) {
-}
+      interned_mojo_interface_tag_(storage->InternString(kMojoIntefaceTagKey)),
+      interned_obfuscated_view_dump_class_name_flat_key_(
+          storage->InternString(kObfuscatedViewDumpClassNameFlatKey)) {}
 
-bool ArgsTranslationTable::NeedsTranslation(StringId key_id,
+bool ArgsTranslationTable::NeedsTranslation(StringId flat_key_id,
+                                            StringId key_id,
                                             Variadic::Type type) const {
-  return KeyIdAndTypeToEnum(key_id, type).has_value();
+  return KeyIdAndTypeToEnum(flat_key_id, key_id, type).has_value();
 }
 
 void ArgsTranslationTable::TranslateArgs(
@@ -105,9 +109,10 @@
   base::Optional<uint64_t> rel_pc;
 
   for (const auto& arg : arg_set) {
-    const auto key_type = KeyIdAndTypeToEnum(arg.key, arg.value.type);
+    const auto key_type =
+        KeyIdAndTypeToEnum(arg.flat_key, arg.key, arg.value.type);
     if (!key_type.has_value()) {
-      inserter.AddArg(arg.key, arg.value, arg.update_policy);
+      inserter.AddArg(arg.flat_key, arg.key, arg.value, arg.update_policy);
       continue;
     }
 
@@ -158,6 +163,17 @@
         }
         break;
       }
+      case KeyType::kClassName: {
+        const base::Optional<StringId> translated_class_name =
+            TranslateClassName(arg.value.string_value);
+        if (translated_class_name) {
+          inserter.AddArg(arg.flat_key, arg.key,
+                          Variadic::String(*translated_class_name));
+        } else {
+          inserter.AddArg(arg.flat_key, arg.key, arg.value);
+        }
+        break;
+      }
       case KeyType::kMojoMethodMappingId: {
         mapping_id = arg.value.uint_value;
         break;
@@ -172,28 +188,32 @@
 }
 
 base::Optional<ArgsTranslationTable::KeyType>
-ArgsTranslationTable::KeyIdAndTypeToEnum(StringId key_id,
+ArgsTranslationTable::KeyIdAndTypeToEnum(StringId flat_key_id,
+                                         StringId key_id,
                                          Variadic::Type type) const {
-  if (type != Variadic::Type::kUint) {
-    return base::nullopt;
-  }
-  if (key_id == interned_chrome_histogram_hash_key_) {
-    return KeyType::kChromeHistogramHash;
-  }
-  if (key_id == interned_chrome_user_event_hash_key_) {
-    return KeyType::kChromeUserEventHash;
-  }
-  if (key_id == interned_chrome_performance_mark_mark_hash_key_) {
-    return KeyType::kChromePerformanceMarkMarkHash;
-  }
-  if (key_id == interned_chrome_performance_mark_site_hash_key_) {
-    return KeyType::kChromePerformanceMarkSiteHash;
-  }
-  if (key_id == interned_mojo_method_mapping_id_) {
-    return KeyType::kMojoMethodMappingId;
-  }
-  if (key_id == interned_mojo_method_rel_pc_) {
-    return KeyType::kMojoMethodRelPc;
+  if (type == Variadic::Type::kUint) {
+    if (key_id == interned_chrome_histogram_hash_key_) {
+      return KeyType::kChromeHistogramHash;
+    }
+    if (key_id == interned_chrome_user_event_hash_key_) {
+      return KeyType::kChromeUserEventHash;
+    }
+    if (key_id == interned_chrome_performance_mark_mark_hash_key_) {
+      return KeyType::kChromePerformanceMarkMarkHash;
+    }
+    if (key_id == interned_chrome_performance_mark_site_hash_key_) {
+      return KeyType::kChromePerformanceMarkSiteHash;
+    }
+    if (key_id == interned_mojo_method_mapping_id_) {
+      return KeyType::kMojoMethodMappingId;
+    }
+    if (key_id == interned_mojo_method_rel_pc_) {
+      return KeyType::kMojoMethodRelPc;
+    }
+  } else if (type == Variadic::Type::kString) {
+    if (flat_key_id == interned_obfuscated_view_dump_class_name_flat_key_) {
+      return KeyType::kClassName;
+    }
   }
   return base::nullopt;
 }
@@ -247,6 +267,11 @@
   return *loc;
 }
 
+base::Optional<StringId> ArgsTranslationTable::TranslateClassName(
+    StringId obfuscated_class_name_id) const {
+  return deobfuscation_mapping_table_.TranslateClass(obfuscated_class_name_id);
+}
+
 void ArgsTranslationTable::EmitMojoMethodLocation(
     base::Optional<uint64_t> mapping_id,
     base::Optional<uint64_t> rel_pc,
diff --git a/src/trace_processor/importers/common/args_translation_table.h b/src/trace_processor/importers/common/args_translation_table.h
index 2ef46af..e1b3178 100644
--- a/src/trace_processor/importers/common/args_translation_table.h
+++ b/src/trace_processor/importers/common/args_translation_table.h
@@ -23,6 +23,7 @@
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/string_view.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
+#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/util/proto_to_args_parser.h"
 
@@ -53,7 +54,9 @@
   explicit ArgsTranslationTable(TraceStorage* storage);
 
   // Returns true if an arg with the given key and type requires translation.
-  bool NeedsTranslation(StringId key_id, Variadic::Type type) const;
+  bool NeedsTranslation(StringId flat_key_id,
+                        StringId key_id,
+                        Variadic::Type type) const;
 
   void TranslateArgs(const ArgsTracker::CompactArgSet& arg_set,
                      ArgsTracker::BoundInserter& inserter) const;
@@ -78,6 +81,10 @@
                                       const SourceLocation& loc) {
     native_symbol_to_location_.Insert(std::make_pair(mapping_id, rel_pc), loc);
   }
+  void AddDeobfuscationMappingTable(
+      DeobfuscationMappingTable deobfuscation_mapping_table) {
+    deobfuscation_mapping_table_ = std::move(deobfuscation_mapping_table);
+  }
 
   base::Optional<base::StringView> TranslateChromeHistogramHashForTesting(
       uint64_t hash) const {
@@ -95,6 +102,10 @@
   TranslateChromePerformanceMarkMarkHashForTesting(uint64_t hash) const {
     return TranslateChromePerformanceMarkMarkHash(hash);
   }
+  base::Optional<StringId> TranslateClassNameForTesting(
+      StringId obfuscated_class_name_id) const {
+    return TranslateClassName(obfuscated_class_name_id);
+  }
 
  private:
   enum class KeyType {
@@ -104,6 +115,7 @@
     kChromePerformanceMarkSiteHash = 3,
     kMojoMethodMappingId = 4,
     kMojoMethodRelPc = 5,
+    kClassName = 6,
   };
 
   static constexpr char kChromeHistogramHashKey[] =
@@ -135,6 +147,9 @@
   static constexpr char kMojoIntefaceTagKey[] =
       "chrome_mojo_event_info.mojo_interface_tag";
 
+  static constexpr char kObfuscatedViewDumpClassNameFlatKey[] =
+      "android_view_dump.activity.view.class_name";
+
   TraceStorage* storage_;
   StringId interned_chrome_histogram_hash_key_;
   StringId interned_chrome_histogram_name_key_;
@@ -150,6 +165,10 @@
   StringId interned_mojo_method_name_;
   StringId interned_mojo_interface_tag_;
 
+  // A "flat_key" of an argument from the "args" table that has to be
+  // deobfuscated. A Java class name must be contained in this argument.
+  StringId interned_obfuscated_view_dump_class_name_flat_key_;
+
   base::FlatHashMap<uint64_t, std::string> chrome_histogram_hash_to_name_;
   base::FlatHashMap<uint64_t, std::string> chrome_user_event_hash_to_action_;
   base::FlatHashMap<uint64_t, std::string>
@@ -157,10 +176,13 @@
   base::FlatHashMap<uint64_t, std::string>
       chrome_performance_mark_mark_hash_to_name_;
   base::FlatHashMap<NativeSymbolKey, SourceLocation> native_symbol_to_location_;
+  // A translation mapping for obfuscated Java class names and its members.
+  DeobfuscationMappingTable deobfuscation_mapping_table_;
 
   // Returns the corresponding SupportedKey enum if the table knows how to
   // translate the argument with the given key and type, and nullopt otherwise.
-  base::Optional<KeyType> KeyIdAndTypeToEnum(StringId key_id,
+  base::Optional<KeyType> KeyIdAndTypeToEnum(StringId flat_key_id,
+                                             StringId key_id,
                                              Variadic::Type type) const;
 
   base::Optional<base::StringView> TranslateChromeHistogramHash(
@@ -174,6 +196,11 @@
   base::Optional<SourceLocation> TranslateNativeSymbol(MappingId mapping_id,
                                                        uint64_t rel_pc) const;
 
+  // Returns the deobfuscated name of a Java class or base::nullopt if
+  // translation is not found.
+  base::Optional<StringId> TranslateClassName(
+      StringId obfuscated_class_name_id) const;
+
   void EmitMojoMethodLocation(base::Optional<uint64_t> mapping_id,
                               base::Optional<uint64_t> rel_pc,
                               ArgsTracker::BoundInserter& inserter) const;
diff --git a/src/trace_processor/importers/common/args_translation_table_unittest.cc b/src/trace_processor/importers/common/args_translation_table_unittest.cc
index 55cb8f3..904e607 100644
--- a/src/trace_processor/importers/common/args_translation_table_unittest.cc
+++ b/src/trace_processor/importers/common/args_translation_table_unittest.cc
@@ -15,6 +15,8 @@
  */
 
 #include "src/trace_processor/importers/common/args_translation_table.h"
+#include "perfetto/ext/base/optional.h"
+#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
@@ -78,31 +80,83 @@
             base::nullopt);
 }
 
+TEST(ArgsTranslationTable, TranslateClassName) {
+  TraceStorage storage;
+  StringId xyz_id = storage.InternString("xyz");
+  StringId abc_id = storage.InternString("abc");
+  StringId class_x_id = storage.InternString("class_X");
+  DeobfuscationMappingTable deobfuscation_mapping;
+  deobfuscation_mapping.AddClassTranslation(
+      DeobfuscationMappingTable::PackageId{"app", 123}, xyz_id, class_x_id,
+      base::FlatHashMap<StringId, StringId>{});
+  ArgsTranslationTable table(&storage);
+  table.AddDeobfuscationMappingTable(std::move(deobfuscation_mapping));
+
+  EXPECT_EQ(table.TranslateClassNameForTesting(xyz_id),
+            base::Optional<StringId>(class_x_id));
+  EXPECT_EQ(table.TranslateClassNameForTesting(abc_id), base::nullopt);
+}
+
 TEST(ArgsTranslationTable, NeedsTranslation) {
   TraceStorage storage;
   ArgsTranslationTable table(&storage);
 
   EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
+      storage.InternString("chrome_histogram_sample.name_hash"),
+      Variadic::Type::kUint));
+  EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
+      storage.InternString("chrome_user_event.action_hash"),
+      Variadic::Type::kUint));
+  EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
+      storage.InternString("chrome_hashed_performance_mark.site_hash"),
+      Variadic::Type::kUint));
+  EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
+      storage.InternString("chrome_hashed_performance_mark.mark_hash"),
+      Variadic::Type::kUint));
+
+  // A real life case, where flat_key == key.
+  EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("chrome_histogram_sample.name_hash"),
       storage.InternString("chrome_histogram_sample.name_hash"),
       Variadic::Type::kUint));
   EXPECT_TRUE(table.NeedsTranslation(
       storage.InternString("chrome_user_event.action_hash"),
+      storage.InternString("chrome_user_event.action_hash"),
       Variadic::Type::kUint));
   EXPECT_TRUE(table.NeedsTranslation(
       storage.InternString("chrome_hashed_performance_mark.site_hash"),
+      storage.InternString("chrome_hashed_performance_mark.site_hash"),
       Variadic::Type::kUint));
   EXPECT_TRUE(table.NeedsTranslation(
       storage.InternString("chrome_hashed_performance_mark.mark_hash"),
+      storage.InternString("chrome_hashed_performance_mark.mark_hash"),
       Variadic::Type::kUint));
 
   // The key needs translation, but the arg type is wrong (not uint).
   EXPECT_FALSE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
       storage.InternString("chrome_histogram_sample.name_hash"),
       Variadic::Type::kInt));
   // The key does not require translation.
   EXPECT_FALSE(table.NeedsTranslation(
+      storage.InternString("unused_flat_key"),
       storage.InternString("chrome_histogram_sample.name"),
       Variadic::Type::kUint));
+
+  // The key needs translation by flat_key.
+  EXPECT_TRUE(table.NeedsTranslation(
+      storage.InternString("android_view_dump.activity.view.class_name"),
+      storage.InternString("android_view_dump.activity[0].view[0].class_name"),
+      Variadic::Type::kString));
+  // The key does not require translation because flat_key and key are swapped.
+  EXPECT_FALSE(table.NeedsTranslation(
+      storage.InternString("android_view_dump.activity[0].view[0].class_name"),
+      storage.InternString("android_view_dump.activity.view.class_name"),
+      Variadic::Type::kString));
 }
 
 }  // namespace
diff --git a/src/trace_processor/importers/common/deobfuscation_mapping_table.cc b/src/trace_processor/importers/common/deobfuscation_mapping_table.cc
new file mode 100644
index 0000000..af5bbf3
--- /dev/null
+++ b/src/trace_processor/importers/common/deobfuscation_mapping_table.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 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/common/deobfuscation_mapping_table.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+bool DeobfuscationMappingTable::AddClassTranslation(
+    const PackageId& package,
+    StringId obfuscated_class_name,
+    StringId deobfuscated_class_name,
+    base::FlatHashMap<StringId, StringId> obfuscated_to_deobfuscated_members) {
+  if (PERFETTO_UNLIKELY(!default_package_id_)) {
+    default_package_id_ = package;
+  }
+
+  ObfuscatedClassesToMembers& classes_to_members =
+      class_per_package_translation_[package];
+  return classes_to_members
+      .Insert(obfuscated_class_name,
+              ClassTranslation{deobfuscated_class_name,
+                               std::move(obfuscated_to_deobfuscated_members)})
+      .second;
+}
+
+base::Optional<StringId> DeobfuscationMappingTable::TranslateClass(
+    StringId obfuscated_class_name) const {
+  if (PERFETTO_UNLIKELY(!default_package_id_.has_value())) {
+    return base::nullopt;
+  }
+  return TranslateClass(default_package_id_.value(), obfuscated_class_name);
+}
+
+base::Optional<StringId> DeobfuscationMappingTable::TranslateClass(
+    const PackageId& package,
+    StringId obfuscated_class_name) const {
+  const ObfuscatedClassesToMembers* classes_translation_ptr =
+      class_per_package_translation_.Find(package);
+  if (classes_translation_ptr == nullptr) {
+    return base::nullopt;
+  }
+  const ClassTranslation* class_translation_ptr =
+      classes_translation_ptr->Find(obfuscated_class_name);
+  if (class_translation_ptr == nullptr) {
+    return base::nullopt;
+  }
+  return class_translation_ptr->deobfuscated_class_name;
+}
+
+base::Optional<StringId> DeobfuscationMappingTable::TranslateMember(
+    const PackageId& package,
+    StringId obfuscated_class_name,
+    StringId obfuscated_member) const {
+  const ObfuscatedClassesToMembers* classes_translation_ptr =
+      class_per_package_translation_.Find(package);
+  if (classes_translation_ptr == nullptr) {
+    return base::nullopt;
+  }
+
+  const ClassTranslation* class_translation_ptr =
+      classes_translation_ptr->Find(obfuscated_class_name);
+  if (class_translation_ptr == nullptr) {
+    return base::nullopt;
+  }
+
+  const StringId* member_translation_ptr =
+      class_translation_ptr->members.Find(obfuscated_member);
+  if (member_translation_ptr == nullptr) {
+    return base::nullopt;
+  }
+  return *member_translation_ptr;
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/common/deobfuscation_mapping_table.h b/src/trace_processor/importers/common/deobfuscation_mapping_table.h
new file mode 100644
index 0000000..7022b19
--- /dev/null
+++ b/src/trace_processor/importers/common/deobfuscation_mapping_table.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 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_COMMON_DEOBFUSCATION_MAPPING_TABLE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_DEOBFUSCATION_MAPPING_TABLE_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/hash.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Constains deobfuscation for Java class names and its members per |PackageId|.
+class DeobfuscationMappingTable {
+ public:
+  struct PackageId {
+    std::string package_name;
+    int64_t version_code;
+
+    bool operator==(const PackageId& other) const {
+      return package_name == other.package_name &&
+             version_code == other.version_code;
+    }
+  };
+
+  // For the given |package| and |obfuscated_class_name| adds translations of
+  // the class and its members.
+  //
+  // Returns `true` if the translation for the given class
+  // was inserted, `false` if there is already a translation for the given
+  // class.
+  bool AddClassTranslation(
+      const PackageId& package,
+      StringId obfuscated_class_name,
+      StringId deobfuscated_class_name,
+      base::FlatHashMap<StringId, StringId> obfuscated_to_deobfuscated_members);
+
+  // These functions return the deobfuscated class/member name from an
+  // obfuscated class/member name.
+  // If a package is not provided, the |default_package_id_| is used.
+  // If translation is not found, returns base::nullopt.
+
+  base::Optional<StringId> TranslateClass(StringId obfuscated_class_name) const;
+
+  base::Optional<StringId> TranslateClass(const PackageId& package,
+                                          StringId obfuscated_class_name) const;
+
+  base::Optional<StringId> TranslateMember(const PackageId& package,
+                                           StringId obfuscated_class_name,
+                                           StringId obfuscated_member) const;
+
+ private:
+  struct PackageIdHash {
+    std::size_t operator()(PackageId const& p) const noexcept {
+      return static_cast<std::size_t>(
+          base::Hasher::Combine(p.package_name, p.version_code));
+    }
+  };
+
+  using ObfuscatedToDeobfuscatedMembers = base::FlatHashMap<StringId, StringId>;
+  struct ClassTranslation {
+    StringId deobfuscated_class_name;
+    ObfuscatedToDeobfuscatedMembers members;
+  };
+
+  using ObfuscatedClassesToMembers =
+      base::FlatHashMap<StringId, ClassTranslation>;
+  base::FlatHashMap<PackageId, ObfuscatedClassesToMembers, PackageIdHash>
+      class_per_package_translation_;
+
+  // To translate entities which don't have a package id, we will use
+  // |default_package_id_|. |default_package_id_| is a package id of the first
+  // inserted entity with a package id;
+  // We need this because curently TraceProcessor doesn't use the package
+  // version of the arguments.
+  // TODO(b/244700870): start use the package version of arguments.
+  base::Optional<PackageId> default_package_id_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_DEOBFUSCATION_MAPPING_TABLE_H_
diff --git a/src/trace_processor/importers/common/deobfuscation_mapping_table_unittest.cc b/src/trace_processor/importers/common/deobfuscation_mapping_table_unittest.cc
new file mode 100644
index 0000000..5b24492
--- /dev/null
+++ b/src/trace_processor/importers/common/deobfuscation_mapping_table_unittest.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 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/common/deobfuscation_mapping_table.h"
+#include <string>
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+using PackageId = DeobfuscationMappingTable::PackageId;
+
+TEST(DeobfuscationMappingTable, EmptyTableByDefault) {
+  TraceStorage storage;
+  StringId xyz_id = storage.InternString("xyz");
+
+  DeobfuscationMappingTable table;
+  EXPECT_EQ(table.TranslateClass(xyz_id), base::nullopt);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app", 123}, xyz_id), base::nullopt);
+}
+
+TEST(DeobfuscationMappingTable, TranslateClassSingleInsert) {
+  TraceStorage storage;
+  StringId xyz_id = storage.InternString("xyz");
+  StringId abc_id = storage.InternString("abc");
+  StringId class_x_id = storage.InternString("class_X");
+
+  DeobfuscationMappingTable table;
+  table.AddClassTranslation(PackageId{"app", 123}, xyz_id, class_x_id,
+                            base::FlatHashMap<StringId, StringId>{});
+  EXPECT_EQ(table.TranslateClass(xyz_id), class_x_id);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app", 123}, xyz_id), class_x_id);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app", 124}, xyz_id), base::nullopt);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app", 123}, abc_id), base::nullopt);
+}
+
+TEST(DeobfuscationMappingTable, TranslateClassMultipleInsert) {
+  TraceStorage storage;
+  StringId xyz_id = storage.InternString("xyz");
+  StringId abc_id = storage.InternString("abc");
+  StringId class_x_id = storage.InternString("class_X");
+  StringId class_y_id = storage.InternString("class_Y");
+  StringId class_a_id = storage.InternString("class_A");
+
+  DeobfuscationMappingTable table;
+  table.AddClassTranslation(PackageId{"app1", 123}, xyz_id, class_x_id,
+                            base::FlatHashMap<StringId, StringId>{});
+  table.AddClassTranslation(PackageId{"app2", 123}, xyz_id, class_y_id,
+                            base::FlatHashMap<StringId, StringId>{});
+  table.AddClassTranslation(PackageId{"app3", 123}, abc_id, class_a_id,
+                            base::FlatHashMap<StringId, StringId>{});
+  EXPECT_EQ(table.TranslateClass(xyz_id), class_x_id);
+  EXPECT_EQ(table.TranslateClass(abc_id), base::nullopt);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app1", 123}, xyz_id), class_x_id);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app2", 123}, xyz_id), class_y_id);
+  EXPECT_EQ(table.TranslateClass(PackageId{"app1", 123}, abc_id),
+            base::nullopt);
+}
+
+TEST(DeobfuscationMappingTable, TranslateMember) {
+  TraceStorage storage;
+  StringId xyz_id = storage.InternString("xyz");
+  StringId abc_id = storage.InternString("abc");
+  StringId class_x_id = storage.InternString("class_X");
+  StringId mmm_1_id = storage.InternString("mmm1");
+  StringId mmm_2_id = storage.InternString("mmm2");
+  StringId mmm_3_id = storage.InternString("mmm3");
+  StringId mmm_4_id = storage.InternString("mmm4");
+  StringId member_1_id = storage.InternString("member_1");
+  StringId member_2_id = storage.InternString("member_2");
+  StringId member_3_id = storage.InternString("member_3");
+
+  base::FlatHashMap<StringId, StringId> members;
+  members[mmm_1_id] = member_1_id;
+  members[mmm_2_id] = member_2_id;
+  members[mmm_3_id] = member_3_id;
+  DeobfuscationMappingTable table;
+  table.AddClassTranslation(PackageId{"app1", 123}, xyz_id, class_x_id,
+                            std::move(members));
+  EXPECT_EQ(table.TranslateMember(PackageId{"app1", 123}, xyz_id, mmm_2_id),
+            member_2_id);
+  EXPECT_EQ(table.TranslateMember(PackageId{"app1", 123}, xyz_id, mmm_4_id),
+            base::nullopt);
+  EXPECT_EQ(table.TranslateMember(PackageId{"app1", 123}, abc_id, mmm_2_id),
+            base::nullopt);
+  EXPECT_EQ(table.TranslateMember(PackageId{"app1", 124}, xyz_id, mmm_2_id),
+            base::nullopt);
+}
+
+}  // namespace
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index 6010643..3c3e3e2 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -18,9 +18,11 @@
 #include <string>
 
 #include "perfetto/base/logging.h"
+#include "perfetto/ext/base/flat_hash_map.h"
 #include "perfetto/ext/base/string_utils.h"
 #include "src/trace_processor/importers/common/args_translation_table.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/proto/heap_profile_tracker.h"
@@ -503,6 +505,7 @@
                                               PacketSequenceStateGeneration*,
                                               uint32_t /* seq_id */,
                                               ConstBytes blob) {
+  DeobfuscationMappingTable deobfuscation_mapping_table;
   protos::pbzero::DeobfuscationMapping::Decoder deobfuscation_mapping(
       blob.data, blob.size);
   if (deobfuscation_mapping.package_name().size == 0)
@@ -517,6 +520,7 @@
   for (auto class_it = deobfuscation_mapping.obfuscated_classes(); class_it;
        ++class_it) {
     protos::pbzero::ObfuscatedClass::Decoder cls(*class_it);
+    base::FlatHashMap<StringId, StringId> obfuscated_to_deobfuscated_members;
     for (auto member_it = cls.obfuscated_methods(); member_it; ++member_it) {
       protos::pbzero::ObfuscatedMember::Decoder member(*member_it);
       std::string merged_obfuscated = cls.obfuscated_name().ToStdString() +
@@ -556,8 +560,21 @@
             context_->storage->InternString(
                 base::StringView(merged_deobfuscated)));
       }
+      obfuscated_to_deobfuscated_members[context_->storage->InternString(
+          member.obfuscated_name())] =
+          context_->storage->InternString(member.deobfuscated_name());
     }
+    // Members can contain a class name (e.g "ClassA.FunctionF")
+    deobfuscation_mapping_table.AddClassTranslation(
+        DeobfuscationMappingTable::PackageId{
+            deobfuscation_mapping.package_name().ToStdString(),
+            deobfuscation_mapping.version_code()},
+        context_->storage->InternString(cls.obfuscated_name()),
+        context_->storage->InternString(cls.deobfuscated_name()),
+        std::move(obfuscated_to_deobfuscated_members));
   }
+  context_->args_translation_table->AddDeobfuscationMappingTable(
+      std::move(deobfuscation_mapping_table));
 }
 
 void ProfileModule::ParseSmapsPacket(int64_t ts, ConstBytes blob) {
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index a3392f2..1f996db 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -21,6 +21,7 @@
 #include "src/trace_processor/importers/common/args_translation_table.h"
 #include "src/trace_processor/importers/common/chunked_trace_reader.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
 #include "src/trace_processor/importers/common/global_args_tracker.h"
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index a96462f..db5efaf 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -44,6 +44,7 @@
 class AndroidProbesTracker;
 class ChunkedTraceReader;
 class ClockTracker;
+class DeobfuscationMappingTable;
 class EventTracker;
 class ForwardingTraceParser;
 class FtraceModule;
diff --git a/test/trace_processor/translation/index b/test/trace_processor/translation/index
index 7b03b51..7ecd49c 100644
--- a/test/trace_processor/translation/index
+++ b/test/trace_processor/translation/index
@@ -1,3 +1,4 @@
+java_class_name_arg.textproto chrome_args_test.sql java_class_name_arg.out
 chrome_histogram.textproto chrome_args_test.sql chrome_histogram.out
 chrome_user_event.textproto chrome_args_test.sql chrome_user_event.out
 chrome_performance_mark.textproto chrome_args_test.sql chrome_performance_mark.out
diff --git a/test/trace_processor/translation/java_class_name_arg.out b/test/trace_processor/translation/java_class_name_arg.out
new file mode 100644
index 0000000..df1ebfb
--- /dev/null
+++ b/test/trace_processor/translation/java_class_name_arg.out
@@ -0,0 +1,10 @@
+"flat_key","key","int_value","string_value"
+"is_root_in_scope","is_root_in_scope",1,"[NULL]"
+"source","source","[NULL]","descriptor"
+"source_id","source_id",0,"[NULL]"
+"android_view_dump.activity.name","android_view_dump.activity[0].name","[NULL]","A1"
+"android_view_dump.activity.view.class_name","android_view_dump.activity[0].view[0].class_name","[NULL]","class_A"
+"android_view_dump.activity.view.class_name","android_view_dump.activity[0].view[1].class_name","[NULL]","def"
+"android_view_dump.activity.view.class_name","android_view_dump.activity[0].view[2].class_name","[NULL]","ghi"
+"android_view_dump.activity.name","android_view_dump.activity[1].name","[NULL]","B1"
+"android_view_dump.activity.view.class_name","android_view_dump.activity[1].view[0].class_name","[NULL]","class_J"
diff --git a/test/trace_processor/translation/java_class_name_arg.textproto b/test/trace_processor/translation/java_class_name_arg.textproto
new file mode 100644
index 0000000..3a633f6
--- /dev/null
+++ b/test/trace_processor/translation/java_class_name_arg.textproto
@@ -0,0 +1,54 @@
+packet {
+  packages_list {
+    packages {
+      name: "package_name_1"
+      version_code: 123
+    }
+  }
+}
+# Packet with arguments
+packet {
+  trusted_packet_sequence_id: 1
+  timestamp: 0
+  incremental_state_cleared: true
+  track_event {
+    categories: "cat1"
+    type: 3
+    name: "name1"
+    [perfetto.protos.ChromeTrackEvent.android_view_dump] {
+      activity {
+        name: "A1"
+        view {
+          class_name: "abc"
+        },
+        view {
+          class_name: "def"
+        },
+        view {
+          class_name: "ghi"
+        }
+      }
+      activity {
+        name: "B1"
+        view {
+          class_name: "jkl"
+        }
+      }
+    }
+  }
+}
+# Packet with DeobfuscationMapping
+packet {
+  deobfuscation_mapping {
+    package_name: "package_name_1"
+    version_code: 123
+    obfuscated_classes {
+        obfuscated_name: "abc"
+        deobfuscated_name: "class_A"
+    }
+    obfuscated_classes {
+        obfuscated_name: "jkl"
+        deobfuscated_name: "class_J"
+    }
+  }
+}
\ No newline at end of file