blob: b9097849ab149fcd250840b97638ea31155aab5e [file] [log] [blame]
#include "installer.h"
#include <unistd.h>
#include <memory>
#include <sstream>
#include "android_studio_version.h"
#include "bash_command.h"
#include "package_manager.h"
#include "utils/current_process.h"
#include "utils/fs/disk_file_system.h"
#include "utils/log.h"
#include "utils/trace.h"
using std::string;
namespace {
bool Exists(const string &who_runs_the_check, const string &path) {
profiler::BashCommandRunner existsCmd("test");
std::stringstream parameters;
parameters << "-e ";
parameters << path;
string output;
return existsCmd.RunAs(parameters.str(), who_runs_the_check, &output);
}
} // namespace
namespace profiler {
Installer::Installer(const char *app_package_name)
: app_package_name_(app_package_name) {}
Installer::Installer(const std::string &app_package_name)
: app_package_name_(app_package_name.c_str()) {}
bool Installer::Install(const string &binary_name, string *error_string) const {
Trace trace("CPU:" + string("Install ") + binary_name.c_str());
Log::I("Request to install sampler in app '%s'", app_package_name_.c_str());
string src_path = CurrentProcess::dir() + binary_name;
// Check if the sampler is already there.
string dst_path;
if (!GetInstallationPath(binary_name, &dst_path, error_string)) {
error_string->append("\n");
error_string->append("Unable to generate installation path");
return false;
}
Log::I("Installing %s to %s", src_path.c_str(), dst_path.c_str());
if (::Exists(app_package_name_, dst_path)) {
Log::I("'%s' executable is already installed (found at '%s').\n",
app_package_name_.c_str(), dst_path.c_str());
return true;
}
Log::I("'%s' executable requires installation (missing from '%s').\n",
app_package_name_.c_str(), dst_path.c_str());
// We need to copy sampler to the app folder.
DiskFileSystem fs;
auto src = fs.GetFile(src_path);
if (!src->Exists()) {
error_string->append("\n");
error_string->append("Source does not exists (" + src_path + ").");
return false;
}
if (!BashCommandRunner::IsRunAsCapable()) {
error_string->append("\n");
error_string->append("System is not run-as capable");
return false;
}
// This abomination spawns two process: A producer piping into a consumer.
// sh -c 'cat SRC | run-as PKG_USER sh -c "cat > DST ; chmod 700 DST"'
BashCommandRunner cmd("cat");
std::stringstream copy_command;
copy_command << src_path;
copy_command << " | ";
copy_command << "run-as ";
copy_command << app_package_name_;
copy_command << " sh -c \"cat > ";
copy_command << dst_path;
copy_command << "; chmod 700 ";
copy_command << dst_path;
copy_command << "\"";
string out;
bool success = cmd.Run(copy_command.str(), &out);
if (!success || !Exists(app_package_name_, dst_path)) {
error_string->append("\n");
error_string->append("cmd:'" + copy_command.str() + "' failed:" + out);
return false;
}
Log::I("%s %s %s", "Installation to'", dst_path.c_str(), "' succeeded.");
return true;
}
bool Installer::Uninstall(const string &binary_path,
string *error_string) const {
DiskFileSystem fs;
auto target = fs.GetFile(binary_path);
if (!target->Exists()) {
error_string->append("\n");
error_string->append("Cannot delete file '" + binary_path +
"': does not exist.");
return false;
}
BashCommandRunner rm("rm");
string parameters;
parameters.append(target->path());
bool success = rm.Run(parameters, error_string);
if (!success || target->Exists()) {
return false;
}
return true;
}
bool Installer::GetInstallationPath(const string &executable_path,
string *install_path,
string *error_string) const {
string error_message;
// Build the installation destination install_path:
PackageManager pm;
string app_base;
bool ret = pm.GetAppDataPath(app_package_name_, &app_base, &error_message);
if (!ret) {
error_string->append(error_message);
return false;
}
Log::I("App %s base is %s", app_package_name_.c_str(), app_base.c_str());
DiskFileSystem fs;
auto binary = fs.GetFile(executable_path);
string binary_filename = binary->name();
install_path->clear();
install_path->append(app_base);
install_path->append("/");
install_path->append(GetBinaryNameForPackage(binary_filename));
return true;
}
const string Installer::GetBinaryNameForPackage(
const string &executable_filename) const {
string binary_name;
binary_name.append(executable_filename);
binary_name.append("-v");
binary_name.append(kAndroidStudioVersion);
return binary_name;
}
} // namespace profiler