blob: 7e2df14f6434abdd73fef23653d4595c2a4849be [file] [log] [blame]
/*
* Copyright (C) 2020 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 "tools/base/deploy/installer/overlay_install.h"
#include <string>
#include "tools/base/deploy/common/event.h"
#include "tools/base/deploy/common/message_pipe_wrapper.h"
#include "tools/base/deploy/common/utils.h"
#include "tools/base/deploy/installer/binary_extract.h"
#include "tools/base/deploy/installer/executor/runas_executor.h"
#include "tools/base/deploy/installer/server/install_client.h"
#include "tools/base/deploy/installer/server/install_server.h"
namespace {
const std::string kAgent = "agent.so";
const std::string kAgentAlt = "agent-alt.so";
const std::string kInstallServer = "install_server";
} // namespace
namespace deploy {
void OverlayInstallCommand::ParseParameters(int argc, char** argv) {
deploy::MessagePipeWrapper wrapper(STDIN_FILENO);
std::string data;
if (!wrapper.Read(&data)) {
return;
}
if (!request_.ParseFromString(data)) {
return;
}
ready_to_run_ = true;
}
void OverlayInstallCommand::Run(proto::InstallerResponse* response) {
proto::OverlayInstallResponse* overlay_response =
response->mutable_overlay_install_response();
if (!ExtractBinaries(workspace_.GetTmpFolder(),
{kAgent, kAgentAlt, kInstallServer})) {
overlay_response->set_status(proto::OverlayInstallResponse::SETUP_FAILED);
ErrEvent("Extracting binaries failed");
return;
}
const std::string server_name =
kInstallServer + "-" + workspace_.GetVersion();
client_ = StartInstallServer(workspace_.GetExecutor(),
workspace_.GetTmpFolder() + kInstallServer,
request_.package_name(), server_name);
if (!client_) {
overlay_response->set_status(
proto::OverlayInstallResponse::START_SERVER_FAILED);
return;
}
SetUpAgent(overlay_response);
UpdateOverlay(overlay_response);
proto::InstallServerResponse install_response;
if (!client_->KillServerAndWait(&install_response)) {
overlay_response->set_status(
proto::OverlayInstallResponse::READ_FROM_SERVER_FAILED);
return;
}
for (int i = 0; i < install_response.events_size(); i++) {
const proto::Event& event = install_response.events(i);
AddRawEvent(ConvertProtoEventToEvent(event));
}
}
void OverlayInstallCommand::SetUpAgent(
proto::OverlayInstallResponse* overlay_response) {
Phase p("SetUpAgent");
std::string version = workspace_.GetVersion() + "-";
std::string code_cache =
"/data/data/" + request_.package_name() + "/code_cache/";
// Determine which agent we need to use.
#if defined(__aarch64__) || defined(__x86_64__)
std::string agent =
request_.arch() == proto::Arch::ARCH_64_BIT ? kAgent : kAgentAlt;
#else
std::string agent = kAgent;
#endif
std::string startup_path = code_cache + "startup_agents/";
std::string studio_path = code_cache + ".studio/";
std::string agent_path = startup_path + version + agent;
std::unordered_set<std::string> missing_files;
CheckFilesExist({startup_path, studio_path, agent_path}, &missing_files);
RunasExecutor run_as(request_.package_name(), workspace_.GetExecutor());
std::string error;
if (missing_files.find(startup_path) != missing_files.end() &&
!run_as.Run("mkdir", {startup_path}, nullptr, &error)) {
ErrEvent("Could not create startup agent directory: " + error);
overlay_response->set_status(proto::OverlayInstallResponse::SETUP_FAILED);
return;
}
if (missing_files.find(studio_path) != missing_files.end() &&
!run_as.Run("mkdir", {studio_path}, nullptr, &error)) {
ErrEvent("Could not create studio directory: " + error);
overlay_response->set_status(proto::OverlayInstallResponse::SETUP_FAILED);
return;
}
std::string tmp_agent = workspace_.GetTmpFolder() + agent;
if (missing_files.find(agent_path) != missing_files.end() &&
!run_as.Run("cp", {"-F", tmp_agent, agent_path}, nullptr, &error)) {
ErrEvent("Could not copy binaries: " + error);
overlay_response->set_status(proto::OverlayInstallResponse::SETUP_FAILED);
return;
}
}
void OverlayInstallCommand::UpdateOverlay(
proto::OverlayInstallResponse* overlay_response) {
Phase p("UpdateOverlay");
proto::InstallServerRequest install_request;
install_request.set_type(proto::InstallServerRequest::HANDLE_REQUEST);
auto overlay_request = install_request.mutable_overlay_request();
overlay_request->set_overlay_id(request_.overlay_id());
overlay_request->set_expected_overlay_id(request_.expected_overlay_id());
const std::string overlay_path =
"/data/data/" + request_.package_name() + "/code_cache";
overlay_request->set_overlay_path(overlay_path);
for (auto overlay_file : request_.overlay_files()) {
auto file = overlay_request->add_files_to_write();
file->set_path(overlay_file.path());
file->set_allocated_content(overlay_file.release_content());
}
for (auto deleted_file : request_.deleted_files()) {
overlay_request->add_files_to_delete(deleted_file);
}
if (!client_->Write(install_request)) {
ErrEvent("Could not write overlay update to install server");
overlay_response->set_status(
proto::OverlayInstallResponse::WRITE_TO_SERVER_FAILED);
return;
}
proto::InstallServerResponse install_response;
if (!client_->Read(&install_response)) {
ErrEvent("Could not read response from install server");
overlay_response->set_status(
proto::OverlayInstallResponse::READ_FROM_SERVER_FAILED);
return;
}
switch (install_response.overlay_response().status()) {
case proto::OverlayUpdateResponse::OK:
overlay_response->set_status(proto::OverlayInstallResponse::OK);
return;
case proto::OverlayUpdateResponse::ID_MISMATCH:
overlay_response->set_status(
proto::OverlayInstallResponse::OVERLAY_ID_MISMATCH);
overlay_response->set_extra(
install_response.overlay_response().error_message());
return;
case proto::OverlayUpdateResponse::UPDATE_FAILED:
overlay_response->set_status(
proto::OverlayInstallResponse::OVERLAY_UPDATE_FAILED);
overlay_response->set_extra(
install_response.overlay_response().error_message());
return;
}
}
bool OverlayInstallCommand::CheckFilesExist(
const std::vector<std::string>& files,
std::unordered_set<std::string>* missing_files) {
Phase p("CheckFilesExist");
proto::InstallServerRequest request;
request.set_type(proto::InstallServerRequest::HANDLE_REQUEST);
for (const std::string& file : files) {
request.mutable_check_request()->add_files(file);
}
proto::InstallServerResponse response;
if (!client_->Write(request) || !client_->Read(&response)) {
return false;
}
missing_files->insert(response.check_response().missing_files().begin(),
response.check_response().missing_files().end());
return true;
}
} // namespace deploy