blob: f5a53638d3e95b1e21e2c08941fd038bcf592de3 [file]
/*
* 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/oid_push.h"
#include <fcntl.h>
#include "tools/base/bazel/native/matryoshka/doll.h"
#include "tools/base/deploy/common/event.h"
#include "tools/base/deploy/common/utils.h"
#include "tools/base/deploy/installer/server/install_client.h"
#include "tools/base/deploy/installer/server/install_server.h"
namespace deploy {
const int kRwFileMode =
S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
const int kRxFileMode =
S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
// 4 Arguments:
// Package Name
// Previous OID
// Next OID
// Clear Overlays (true/false)
void OverlayIdPushCommand::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;
}
bool OverlayIdPushCommand::ExtractBinaries(
const std::string& target_dir,
const std::vector<std::string>& files_to_extract) const {
Phase p("ExtractBinaries");
std::vector<std::unique_ptr<matryoshka::Doll>> dolls;
for (const std::string& file : files_to_extract) {
const std::string tmp_path = target_dir + file;
// If we've already extracted the file, we don't need to re-extract.
if (access(tmp_path.c_str(), F_OK) == 0) {
continue;
}
// Open the matryoshka if we haven't already done so.
if (dolls.empty() && !matryoshka::Open(dolls)) {
ErrEvent("Installer binary does not contain any other binaries.");
return false;
}
// Find the binary that corresponds to this file and write it to disk.
matryoshka::Doll* doll = matryoshka::FindByName(dolls, file);
if (!doll) {
continue;
}
if (!WriteArrayToDisk(doll->content, doll->content_len,
target_dir + file)) {
ErrEvent("Failed writing to disk");
return false;
}
}
return true;
}
bool OverlayIdPushCommand::WriteArrayToDisk(const unsigned char* array,
uint64_t array_len,
const std::string& dst_path) const
noexcept {
Phase p("WriteArrayToDisk");
std::string real_path = workspace_.GetRoot() + dst_path;
int fd = open(real_path.c_str(), O_WRONLY | O_CREAT, kRwFileMode);
if (fd == -1) {
ErrEvent("WriteArrayToDisk, open: "_s + strerror(errno));
return false;
}
int written = write(fd, array, array_len);
if (written == -1) {
ErrEvent("WriteArrayToDisk, write: "_s + strerror(errno));
return false;
}
int close_result = close(fd);
if (close_result == -1) {
ErrEvent("WriteArrayToDisk, close: "_s + strerror(errno));
return false;
}
chmod(real_path.c_str(), kRxFileMode);
return true;
}
void OverlayIdPushCommand::Run(proto::InstallerResponse* response) {
Phase p("Overlay ID Push");
if (!ExtractBinaries(workspace_.GetTmpFolder(), {kInstallServer})) {
// TODO Error Handling
ErrEvent("Extracting binaries failed");
return;
}
auto dump_response = response->mutable_overlayidpush_response();
proto::InstallServerRequest install_request;
install_request.set_type(proto::InstallServerRequest::HANDLE_REQUEST);
auto update_request = install_request.mutable_overlay_request();
update_request->set_expected_overlay_id(request_.prev_oid());
update_request->set_overlay_id(request_.next_oid());
update_request->set_overlay_path("code_cache");
update_request->set_wipe_all_files(request_.wipe_overlays());
std::unique_ptr<InstallClient> client_ = StartInstallServer(
workspace_.GetExecutor(), workspace_.GetTmpFolder() + kInstallServer,
request_.package_name(), kInstallServer + "-" + workspace_.GetVersion());
if (!client_) {
// TODO Error Handling
return;
}
if (!client_->Write(install_request)) {
// TODO Error Handling.
return;
}
// Wait for server overlay update response.
proto::InstallServerResponse install_response;
if (!client_->Read(&install_response)) {
return;
}
if (install_response.overlay_response().status() !=
proto::OverlayUpdateResponse::OK) {
// TODO Error Handling.
}
if (!client_->KillServerAndWait(&install_response)) {
// TODO Error Handling.
return;
}
dump_response->set_status(proto::OverlayIdPushResponse::OK);
}
} // namespace deploy