blob: 9cd7ae068921796d91e2e5af0dfd10d1c7d08b34 [file] [log] [blame]
/*
* Copyright (C) 2016 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 "activity_manager.h"
#include <sys/stat.h>
#include <iostream>
#include <sstream>
#include "utils/clock.h"
#include "utils/current_process.h"
#include "utils/device_info.h"
#include "utils/filesystem_notifier.h"
#include "utils/trace.h"
using std::string;
namespace {
const char *const kAmExecutable = "/system/bin/am";
}
namespace profiler {
ActivityManager::ActivityManager()
: bash_(new BashCommandRunner(kAmExecutable)) {}
bool ActivityManager::StartProfiling(const ProfilingMode profiling_mode,
const string &app_package_name,
int sampling_interval_us,
string *trace_path, string *error_string) {
Trace trace("CPU:StartProfiling ART");
std::lock_guard<std::mutex> lock(profiled_lock_);
if (IsAppProfiled(app_package_name)) {
*error_string = "App is already being profiled with ART";
return false;
}
*trace_path = this->GenerateTracePath(app_package_name);
// Run command via actual am.
std::ostringstream parameters;
parameters << "profile start ";
if (profiling_mode == ActivityManager::SAMPLING) {
// A sample interval in microseconds is required after '--sampling'.
// Note that '--sampling 0' would direct ART into instrumentation mode.
// If there's no '--sampling X', instrumentation is used.
parameters << "--sampling " << sampling_interval_us << " ";
}
if (DeviceInfo::feature_level() >= 26) {
// Use streaming output mode on O or greater.
parameters << "--streaming ";
}
parameters << app_package_name << " " << *trace_path;
if (!bash_->Run(parameters.str(), error_string)) {
*error_string = "Unable to run profile start command";
return false;
}
AddProfiledApp(app_package_name, *trace_path);
return true;
}
bool ActivityManager::StopProfiling(const string &app_package_name,
bool need_result, string *error_string) {
Trace trace("CPU:StopProfiling ART");
std::lock_guard<std::mutex> lock(profiled_lock_);
// Start monitoring trace events (to catch close) so this method only returns
// when the generation of the trace file is finished.
FileSystemNotifier notifier(GetProfiledAppTracePath(app_package_name),
FileSystemNotifier::CLOSE);
RemoveProfiledApp(app_package_name);
if (need_result) {
if (!notifier.IsReadyToNotify()) {
*error_string = "Unable to monitor trace file for completion";
return false;
}
}
// Run stop command via actual am.
string parameters;
parameters.append("profile stop ");
parameters.append(app_package_name);
if (!bash_->Run(parameters, error_string)) {
*error_string = "Unable to run profile stop command";
return false;
}
if (need_result) {
// Wait until ART has finished writing the trace to the file and closed the
// file.
if (!notifier.WaitUntilEventOccurs()) {
*error_string = "Wait for ART trace file failed.";
return false;
}
}
return true;
}
bool ActivityManager::TriggerHeapDump(int pid, const std::string &file_path,
std::string *error_string) const {
std::stringstream ss;
ss << "dumpheap " << pid << " " << file_path;
return bash_->Run(ss.str(), error_string);
}
std::string ActivityManager::GenerateTracePath(
const std::string &app_package_name) const {
// TODO: The activity manager should be a component of the daemon.
// And it should use the daemon's steady clock.
SteadyClock clock;
std::stringstream path;
path << CurrentProcess::dir();
path << app_package_name;
path << "-";
path << clock.GetCurrentTime();
path << ".art_trace";
return path.str();
}
ActivityManager *ActivityManager::Instance() {
static ActivityManager *instance = new ActivityManager();
return instance;
}
bool ActivityManager::IsAppProfiled(const std::string &app_package_name) const {
return profiled_.find(app_package_name) != profiled_.end();
}
void ActivityManager::AddProfiledApp(const std::string &app_package_name,
const std::string &trace_path) {
ArtOnGoingProfiling profilingEntry;
profilingEntry.trace_path = trace_path;
profilingEntry.app_pkg_name = app_package_name;
profiled_[app_package_name] = profilingEntry;
}
void ActivityManager::RemoveProfiledApp(const std::string &app_package_name) {
profiled_.erase(app_package_name);
}
string ActivityManager::GetProfiledAppTracePath(
const std::string &app_package_name) const {
auto it = profiled_.find(app_package_name);
return it->second.trace_path;
}
} // namespace profiler