From db19d6d5d093c652ecf79f82bf3826f09e9ce21f Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 12 May 2021 17:36:02 -0700 Subject: simpleperf: add --show-app-type in simpleperf_app_runner. It shows whether an app is debuggable or profileable. Use it to decide whether to use run-as or simpleperf_app_runner to profile an app. Also use it to store app_type in meta_info. Bug: 186469540 Test: run simpleperf_unit_test. Test: run CtsSimpleperfTestCases. Change-Id: If36dc3d88a7ac4cbca803e5b0565a4fdda2755cb --- simpleperf/cmd_record.cpp | 3 ++ simpleperf/cmd_record_test.cpp | 3 +- simpleperf/environment.cpp | 55 ++++++++++++++++------ simpleperf/environment.h | 1 + simpleperf/environment_test.cpp | 7 +++ .../simpleperf_app_runner.cpp | 28 +++++++++-- 6 files changed, 78 insertions(+), 19 deletions(-) diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 2e646bb4..7cffa6f5 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -1916,6 +1916,9 @@ bool RecordCommand::DumpMetaInfoFeature(bool kernel_symbols_available) { info_map["android_version"] = android::base::GetProperty("ro.build.version.release", ""); if (!app_package_name_.empty()) { info_map["app_package_name"] = app_package_name_; + if (IsRoot()) { + info_map["app_type"] = GetAppType(app_package_name_); + } } if (event_selection_set_.HasAuxTrace()) { // used by --exclude-perf in cmd_inject.cpp diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index 3e0b9e1a..9d318a50 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -754,8 +754,7 @@ TEST(record_cmd, app_option_for_debuggable_app) { SetRunInAppToolForTesting(true, false); TestRecordingApps("com.android.simpleperf.debuggable", "debuggable"); SetRunInAppToolForTesting(false, true); - // Although the app is actually debuggable, we profile the app using simpleperf_app_runner. - TestRecordingApps("com.android.simpleperf.debuggable", "profileable"); + TestRecordingApps("com.android.simpleperf.debuggable", "debuggable"); } TEST(record_cmd, app_option_for_profileable_app) { diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp index 4fe908fa..4c960350 100644 --- a/simpleperf/environment.cpp +++ b/simpleperf/environment.cpp @@ -530,9 +530,10 @@ std::set WaitForAppProcesses(const std::string& package_name) { namespace { -bool IsAppDebuggable(const std::string& user_id, const std::string& package_name) { - return Workload::RunCmd( - {"run-as", package_name, "--user", user_id, "echo", ">/dev/null", "2>/dev/null"}, false); +bool IsAppDebuggable(int user_id, const std::string& package_name) { + return Workload::RunCmd({"run-as", package_name, "--user", std::to_string(user_id), "echo", + ">/dev/null", "2>/dev/null"}, + false); } class InAppRunner { @@ -696,10 +697,6 @@ class RunAs : public InAppRunner { }; bool RunAs::Prepare() { - // Test if run-as can access the package. - if (!IsAppDebuggable(user_id_, package_name_)) { - return false; - } // run-as can't run /data/local/tmp/simpleperf directly. So copy simpleperf binary if needed. if (!android::base::Readlink("/proc/self/exe", &simpleperf_path_)) { PLOG(ERROR) << "ReadLink failed"; @@ -722,8 +719,12 @@ bool RunAs::Prepare() { class SimpleperfAppRunner : public InAppRunner { public: - SimpleperfAppRunner(int user_id, const std::string& package_name) - : InAppRunner(user_id, package_name) {} + SimpleperfAppRunner(int user_id, const std::string& package_name, const std::string app_type) + : InAppRunner(user_id, package_name) { + // On Android < S, the app type is unknown before running simpleperf_app_runner. Assume it's + // profileable. + app_type_ = app_type == "unknown" ? "profileable" : app_type; + } bool Prepare() override { return GetAndroidVersion() >= kAndroidVersionQ; } protected: @@ -736,10 +737,12 @@ class SimpleperfAppRunner : public InAppRunner { args.emplace_back(cmd); if (cmd == "record" && GetAndroidVersion() >= kAndroidVersionS) { args.emplace_back("--add-meta-info"); - args.emplace_back("app_type=profileable"); + args.emplace_back("app_type=" + app_type_); } return args; } + + std::string app_type_; }; } // namespace @@ -766,21 +769,45 @@ static int GetCurrentUserId() { return 0; } +std::string GetAppType(const std::string& app_package_name) { + if (GetAndroidVersion() < kAndroidVersionS) { + return "unknown"; + } + std::string cmd = "simpleperf_app_runner " + app_package_name + " --show-app-type"; + std::unique_ptr fp(popen(cmd.c_str(), "re"), pclose); + if (fp) { + char buf[128]; + if (fgets(buf, sizeof(buf), fp.get()) != nullptr) { + return android::base::Trim(buf); + } + } + // Can't get app_type. It means the app doesn't exist. + return "not_exist"; +} + bool RunInAppContext(const std::string& app_package_name, const std::string& cmd, const std::vector& args, size_t workload_args_size, const std::string& output_filepath, bool need_tracepoint_events) { int user_id = GetCurrentUserId(); std::unique_ptr in_app_runner; - if (allow_run_as) { + + std::string app_type = GetAppType(app_package_name); + if (app_type == "unknown" && IsAppDebuggable(user_id, app_package_name)) { + app_type = "debuggable"; + } + + if (allow_run_as && app_type == "debuggable") { in_app_runner.reset(new RunAs(user_id, app_package_name)); if (!in_app_runner->Prepare()) { in_app_runner = nullptr; } } if (!in_app_runner && allow_simpleperf_app_runner) { - in_app_runner.reset(new SimpleperfAppRunner(user_id, app_package_name)); - if (!in_app_runner->Prepare()) { - in_app_runner = nullptr; + if (app_type == "debuggable" || app_type == "profileable" || app_type == "unknown") { + in_app_runner.reset(new SimpleperfAppRunner(user_id, app_package_name, app_type)); + if (!in_app_runner->Prepare()) { + in_app_runner = nullptr; + } } } if (!in_app_runner) { diff --git a/simpleperf/environment.h b/simpleperf/environment.h index 665a7c53..180b98c3 100644 --- a/simpleperf/environment.h +++ b/simpleperf/environment.h @@ -94,6 +94,7 @@ void SetRunInAppToolForTesting(bool run_as, bool simpleperf_app_runner); // for bool RunInAppContext(const std::string& app_package_name, const std::string& cmd, const std::vector& args, size_t workload_args_size, const std::string& output_filepath, bool need_tracepoint_events); +std::string GetAppType(const std::string& app_package_name); void AllowMoreOpenedFiles(); diff --git a/simpleperf/environment_test.cpp b/simpleperf/environment_test.cpp index 596b632a..a95caca8 100644 --- a/simpleperf/environment_test.cpp +++ b/simpleperf/environment_test.cpp @@ -129,3 +129,10 @@ TEST(environment, GetProcessUid) { ASSERT_TRUE(uid.has_value()); ASSERT_EQ(uid.value(), getuid()); } + +TEST(environment, GetAppType) { + TEST_REQUIRE_APPS(); + ASSERT_EQ(GetAppType("com.android.simpleperf.debuggable"), "debuggable"); + ASSERT_EQ(GetAppType("com.android.simpleperf.profileable"), "profileable"); + ASSERT_EQ(GetAppType("com.android.simpleperf.app_not_exist"), "not_exist"); +} diff --git a/simpleperf/simpleperf_app_runner/simpleperf_app_runner.cpp b/simpleperf/simpleperf_app_runner/simpleperf_app_runner.cpp index 20329d0d..f3e6b4b5 100644 --- a/simpleperf/simpleperf_app_runner/simpleperf_app_runner.cpp +++ b/simpleperf/simpleperf_app_runner/simpleperf_app_runner.cpp @@ -164,9 +164,16 @@ static void CheckSimpleperfArguments(std::string_view cmd_name, char** args) { int main(int argc, char* argv[]) { if (argc < 3) { - error(1, 0, - "usage: simpleperf_app_runner package_name [--user uid] simpleperf_cmd " - "simpleperf_cmd_args..."); + fprintf( + stderr, + // clang-format off +"Usage: simpleperf_app_runner package_name [options] [simpleperf cmd simpleperf_cmd_args]\n" +"Options:\n" +"--user uid profile app process run by uid\n" +"--show-app-type show if the app is debuggable or profileable\n" + // clang-format on + ); + return 1; } int i = 1; char* pkgname = argv[i++]; @@ -177,6 +184,21 @@ int main(int argc, char* argv[]) { } i += 2; } + if (i < argc && strcmp(argv[i], "--show-app-type") == 0) { + pkg_info* info = ReadPackageInfo(pkgname); + if (info == nullptr) { + error(1, 0, "failed to find package %s", pkgname); + } + if (info->debuggable) { + printf("debuggable\n"); + } else if (info->profileable_from_shell) { + printf("profileable\n"); + } else { + printf("non_profileable\n"); + } + return 0; + } + if (i == argc) { error(1, 0, "no simpleperf command name"); } -- cgit v1.2.3