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