summaryrefslogtreecommitdiff
path: root/simpleperf/report_utils_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/report_utils_test.cpp')
-rw-r--r--simpleperf/report_utils_test.cpp170
1 files changed, 169 insertions, 1 deletions
diff --git a/simpleperf/report_utils_test.cpp b/simpleperf/report_utils_test.cpp
index 401bbd7e..55771218 100644
--- a/simpleperf/report_utils_test.cpp
+++ b/simpleperf/report_utils_test.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <stdlib.h>
+
#include <string>
#include <vector>
@@ -25,6 +27,47 @@
using namespace simpleperf;
+TEST(ProguardMappingRetrace, smoke) {
+ TemporaryFile tmpfile;
+ close(tmpfile.release());
+ ASSERT_TRUE(
+ android::base::WriteStringToFile("original.class.A -> A:\n"
+ "\n"
+ " void method_a() -> a\n"
+ " void method_b() -> b\n"
+ " # {\"id\":\"com.android.tools.r8.synthesized\"}\n"
+ " # some other comments\n"
+ " void original.class.M.method_c() -> c\n"
+ " void original.class.A.method_d() -> d\n"
+ "original.class.B -> B:\n"
+ "# some other comments\n"
+ "original.class.C -> C:\n"
+ "# {\'id\':\'com.android.tools.r8.synthesized\'}\n",
+ tmpfile.path));
+ ProguardMappingRetrace retrace;
+ ASSERT_TRUE(retrace.AddProguardMappingFile(tmpfile.path));
+ std::string original_name;
+ bool synthesized;
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("A.a", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.A.method_a");
+ ASSERT_FALSE(synthesized);
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("A.b", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.A.method_b");
+ ASSERT_TRUE(synthesized);
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("A.c", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.M.method_c");
+ ASSERT_FALSE(synthesized);
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("A.d", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.A.method_d");
+ ASSERT_FALSE(synthesized);
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("B.b", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.B.b");
+ ASSERT_FALSE(synthesized);
+ ASSERT_TRUE(retrace.DeObfuscateJavaMethods("C.c", &original_name, &synthesized));
+ ASSERT_EQ(original_name, "original.class.C.c");
+ ASSERT_TRUE(synthesized);
+}
+
class CallChainReportBuilderTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -65,6 +108,7 @@ class CallChainReportBuilderTest : public testing::Test {
Symbol("java_method2", 0x3000, 0x100),
Symbol("java_method3", 0x3100, 0x100),
Symbol("obfuscated_class.obfuscated_java_method2", 0x3200, 0x100),
+ Symbol("obfuscated_class.java_method4", 0x3300, 0x100),
});
// Add map layout for libraries used in the thread:
@@ -265,11 +309,12 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
std::vector<uint64_t> fake_ips = {
0x2200, // 2200, // obfuscated_class.obfuscated_java_method
0x3200, // 3200, // obfuscated_class.obfuscated_java_method2
+ 0x3300, // 3300, // obfuscated_class.java_method4
};
CallChainReportBuilder builder(thread_tree);
// Symbol names aren't changed when not given proguard mapping files.
std::vector<CallChainReportEntry> entries = builder.Build(thread, fake_ips, 0);
- ASSERT_EQ(entries.size(), 2);
+ ASSERT_EQ(entries.size(), 3);
ASSERT_EQ(entries[0].ip, 0x2200);
ASSERT_STREQ(entries[0].symbol->DemangledName(), "obfuscated_class.obfuscated_java_method");
ASSERT_EQ(entries[0].dso->Path(), fake_dex_file_path);
@@ -280,6 +325,11 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
ASSERT_EQ(entries[1].dso->Path(), fake_jit_cache_path);
ASSERT_EQ(entries[1].vaddr_in_file, 0x3200);
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+ ASSERT_EQ(entries[2].ip, 0x3300);
+ ASSERT_STREQ(entries[2].symbol->DemangledName(), "obfuscated_class.java_method4");
+ ASSERT_EQ(entries[2].dso->Path(), fake_jit_cache_path);
+ ASSERT_EQ(entries[2].vaddr_in_file, 0x3300);
+ ASSERT_EQ(entries[2].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
// Symbol names are changed when given a proguard mapping file.
TemporaryFile tmpfile;
@@ -294,6 +344,47 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
tmpfile.path));
builder.AddProguardMappingFile(tmpfile.path);
entries = builder.Build(thread, fake_ips, 0);
+ ASSERT_EQ(entries.size(), 3);
+ ASSERT_EQ(entries[0].ip, 0x2200);
+ ASSERT_STREQ(entries[0].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read");
+ ASSERT_EQ(entries[0].dso->Path(), fake_dex_file_path);
+ ASSERT_EQ(entries[0].vaddr_in_file, 0x200);
+ ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
+ ASSERT_EQ(entries[1].ip, 0x3200);
+ ASSERT_STREQ(entries[1].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read2");
+ ASSERT_EQ(entries[1].dso->Path(), fake_jit_cache_path);
+ ASSERT_EQ(entries[1].vaddr_in_file, 0x3200);
+ ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+ ASSERT_STREQ(entries[2].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.java_method4");
+ ASSERT_EQ(entries[2].dso->Path(), fake_jit_cache_path);
+ ASSERT_EQ(entries[2].vaddr_in_file, 0x3300);
+ ASSERT_EQ(entries[2].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+}
+
+TEST_F(CallChainReportBuilderTest, not_remove_synthesized_frame_by_default) {
+ std::vector<uint64_t> fake_ips = {
+ 0x2200, // 2200, // obfuscated_class.obfuscated_java_method
+ 0x3200, // 3200, // obfuscated_class.obfuscated_java_method2
+ };
+
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "android.support.v4.app.RemoteActionCompatParcelizer -> obfuscated_class:\n"
+ " 13:13:androidx.core.app.RemoteActionCompat read(androidx.versionedparcelable.Versioned"
+ "Parcel) -> obfuscated_java_method\n"
+ " # {\"id\":\"com.android.tools.r8.synthesized\"}\n"
+ " 13:13:androidx.core.app.RemoteActionCompat "
+ "android.support.v4.app.RemoteActionCompatParcelizer.read2(androidx.versionedparcelable."
+ "VersionedParcel) -> obfuscated_java_method2",
+ tmpfile.path));
+
+ // By default, synthesized frames are kept.
+ CallChainReportBuilder builder(thread_tree);
+ builder.AddProguardMappingFile(tmpfile.path);
+ std::vector<CallChainReportEntry> entries = builder.Build(thread, fake_ips, 0);
ASSERT_EQ(entries.size(), 2);
ASSERT_EQ(entries[0].ip, 0x2200);
ASSERT_STREQ(entries[0].symbol->DemangledName(),
@@ -309,6 +400,41 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+TEST_F(CallChainReportBuilderTest, remove_synthesized_frame_with_env_variable) {
+ // Windows doesn't support setenv and unsetenv. So don't test on it.
+#if !defined(__WIN32)
+ std::vector<uint64_t> fake_ips = {
+ 0x2200, // 2200, // obfuscated_class.obfuscated_java_method
+ 0x3200, // 3200, // obfuscated_class.obfuscated_java_method2
+ };
+
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "android.support.v4.app.RemoteActionCompatParcelizer -> obfuscated_class:\n"
+ " 13:13:androidx.core.app.RemoteActionCompat read(androidx.versionedparcelable.Versioned"
+ "Parcel) -> obfuscated_java_method\n"
+ " # {\"id\":\"com.android.tools.r8.synthesized\"}\n"
+ " 13:13:androidx.core.app.RemoteActionCompat "
+ "android.support.v4.app.RemoteActionCompatParcelizer.read2(androidx.versionedparcelable."
+ "VersionedParcel) -> obfuscated_java_method2",
+ tmpfile.path));
+
+ // With environment variable set, synthesized frames are removed.
+ ASSERT_EQ(setenv("REMOVE_R8_SYNTHESIZED_FRAME", "1", 1), 0);
+ CallChainReportBuilder builder(thread_tree);
+ ASSERT_EQ(unsetenv("REMOVE_R8_SYNTHESIZED_FRAME"), 0);
+ builder.AddProguardMappingFile(tmpfile.path);
+ std::vector<CallChainReportEntry> entries = builder.Build(thread, fake_ips, 0);
+ ASSERT_EQ(entries.size(), 1);
+ ASSERT_EQ(entries[0].ip, 0x3200);
+ ASSERT_STREQ(entries[0].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read2");
+ ASSERT_EQ(entries[0].dso->Path(), fake_jit_cache_path);
+ ASSERT_EQ(entries[0].vaddr_in_file, 0x3200);
+ ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+#endif // !defined(__WIN32)
+}
+
TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file_for_jit_method_with_signature) {
std::vector<uint64_t> fake_ips = {
0x3200, // 3200, // void ctep.v(cteo, ctgc, ctbn)
@@ -413,3 +539,45 @@ TEST_F(CallChainReportBuilderTest, convert_jit_frame_for_jit_method_with_signatu
ASSERT_EQ(entries[1].vaddr_in_file, 0x200);
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+
+class ThreadReportBuilderTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ thread_tree.SetThreadName(1, 1, "thread1");
+ thread_tree.SetThreadName(1, 2, "thread-pool1");
+ thread_tree.SetThreadName(1, 3, "thread-pool2");
+ }
+
+ bool IsReportEqual(const ThreadReport& report1, const ThreadReport& report2) {
+ return report1.pid == report2.pid && report1.tid == report2.tid &&
+ strcmp(report1.thread_name, report2.thread_name) == 0;
+ }
+
+ ThreadTree thread_tree;
+};
+
+TEST_F(ThreadReportBuilderTest, no_setting) {
+ ThreadReportBuilder builder;
+ ThreadEntry* thread = thread_tree.FindThread(1);
+ ThreadReport report = builder.Build(*thread);
+ ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 1, "thread1")));
+}
+
+TEST_F(ThreadReportBuilderTest, aggregate_threads) {
+ ThreadReportBuilder builder;
+ ASSERT_TRUE(builder.AggregateThreads({"thread-pool.*"}));
+ ThreadEntry* thread = thread_tree.FindThread(1);
+ ThreadReport report = builder.Build(*thread);
+ ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 1, "thread1")));
+ thread = thread_tree.FindThread(2);
+ report = builder.Build(*thread);
+ ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 2, "thread-pool.*")));
+ thread = thread_tree.FindThread(3);
+ report = builder.Build(*thread);
+ ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 2, "thread-pool.*")));
+}
+
+TEST_F(ThreadReportBuilderTest, aggregate_threads_bad_regex) {
+ ThreadReportBuilder builder;
+ ASSERT_FALSE(builder.AggregateThreads({"?thread-pool*"}));
+}