summaryrefslogtreecommitdiff
path: root/host/commands/assemble_cvd/super_image_mixer.cc
diff options
context:
space:
mode:
authorandroid-build-prod (mdb) <android-build-team-robot@google.com>2019-10-18 00:11:55 +0000
committerandroid-build-prod (mdb) <android-build-team-robot@google.com>2019-10-18 00:11:55 +0000
commit403b3b6699f8601f0ade24916a262d53ec63a460 (patch)
tree3ba0856fd908e190970739e703dc4e81ce972e2d /host/commands/assemble_cvd/super_image_mixer.cc
parent5f061bd8e585b607cc0358b7b7d82403eb1c9e7b (diff)
parent6809488b429a1285ef430b56760f50ec20bff92b (diff)
downloadcuttlefish_common-403b3b6699f8601f0ade24916a262d53ec63a460.tar.gz
Snap for 5949240 from 6809488b429a1285ef430b56760f50ec20bff92b to sdk-releaseplatform-tools-29.0.6platform-tools-29.0.5sdk-release
Change-Id: I9a778344c3fee6b838c2a8d6cb445a539161f743
Diffstat (limited to 'host/commands/assemble_cvd/super_image_mixer.cc')
-rw-r--r--host/commands/assemble_cvd/super_image_mixer.cc256
1 files changed, 256 insertions, 0 deletions
diff --git a/host/commands/assemble_cvd/super_image_mixer.cc b/host/commands/assemble_cvd/super_image_mixer.cc
new file mode 100644
index 00000000..061497fa
--- /dev/null
+++ b/host/commands/assemble_cvd/super_image_mixer.cc
@@ -0,0 +1,256 @@
+//
+// Copyright (C) 2019 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 "super_image_mixer.h"
+
+#include <cstdio>
+#include <functional>
+#include <memory>
+
+#include <glog/logging.h>
+
+#include "ziparchive/zip_archive.h"
+#include "ziparchive/zip_writer.h"
+
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/fetcher_config.h"
+
+namespace {
+
+using cvd::FileExists;
+using vsoc::DefaultHostArtifactsPath;
+
+std::string TargetFilesZip(const cvd::FetcherConfig& fetcher_config,
+ cvd::FileSource source) {
+ for (const auto& file_iter : fetcher_config.get_cvd_files()) {
+ if (file_iter.second.source != source) {
+ continue;
+ }
+ std::string expected_substr = "target_files-" + file_iter.second.build_id + ".zip";
+ auto expected_pos = file_iter.first.size() - expected_substr.size();
+ if (file_iter.first.rfind(expected_substr) == expected_pos) {
+ return file_iter.first;
+ }
+ }
+ return "";
+}
+
+class ZipArchiveDeleter {
+public:
+ void operator()(ZipArchive* archive) {
+ CloseArchive(archive);
+ }
+};
+
+using ManagedZipArchive = std::unique_ptr<ZipArchive, ZipArchiveDeleter>;
+
+class CFileCloser {
+public:
+ void operator()(FILE* file) {
+ fclose(file);
+ }
+};
+
+using ManagedCFile = std::unique_ptr<FILE, CFileCloser>;
+
+ManagedZipArchive OpenZipArchive(const std::string& path) {
+ ZipArchive* ptr;
+ int status = OpenArchive(path.c_str(), &ptr);
+ if (status != 0) {
+ LOG(ERROR) << "Could not open archive \"" << path << "\": " << status;
+ return {};
+ }
+ return ManagedZipArchive(ptr);
+}
+
+ManagedCFile OpenFile(const std::string& path, const std::string& mode) {
+ FILE* ptr = fopen(path.c_str(), mode.c_str());
+ if (ptr == nullptr) {
+ int error_num = errno;
+ LOG(ERROR) << "Could not open \"" << path << "\". Error was "
+ << strerror(error_num);
+ return {};
+ }
+ return ManagedCFile(ptr);
+}
+
+const std::string kMiscInfoPath = "META/misc_info.txt";
+const std::string kSystemPath = "IMAGES/system.img";
+const std::string kSystemExtPath = "IMAGES/system_ext.img";
+
+bool CopyZipFileContents(const uint8_t* buf, size_t buf_size, void* cookie) {
+ ZipWriter* out_writer = (ZipWriter*) cookie;
+ int32_t status = out_writer->WriteBytes(buf, buf_size);
+ if (status != 0) {
+ LOG(ERROR) << "Could not write zip file contents, error code " << status;
+ return false;
+ }
+ return true;
+}
+
+bool CombineTargetZipFiles(const std::string& default_target_zip,
+ const std::string& system_target_zip,
+ const std::string& output_path) {
+ auto default_target = OpenZipArchive(default_target_zip);
+ if (!default_target) {
+ LOG(ERROR) << "Could not open " << default_target_zip;
+ return false;
+ }
+ auto system_target = OpenZipArchive(system_target_zip);
+ if (!system_target) {
+ LOG(ERROR) << "Could not open " << system_target_zip;
+ return false;
+ }
+ auto out_file = OpenFile(output_path, "wb");
+ if (!out_file) {
+ LOG(ERROR) << "Could not open " << output_path;
+ return false;
+ }
+ ZipWriter out_writer{out_file.get()};
+
+ ZipEntry entry;
+ if (FindEntry(system_target.get(), kSystemPath, &entry) != 0) {
+ LOG(ERROR) << "System target files zip does not have " << kSystemPath;
+ return false;
+ }
+
+ if (FindEntry(default_target.get(), kMiscInfoPath, &entry) != 0) {
+ LOG(ERROR) << "Default target files zip does not have " << kMiscInfoPath;
+ return false;
+ }
+ out_writer.StartEntry(kMiscInfoPath, 0);
+ ProcessZipEntryContents(
+ default_target.get(), &entry, CopyZipFileContents, (void*) &out_writer);
+ out_writer.FinishEntry();
+
+ bool system_target_has_ext =
+ FindEntry(system_target.get(), kSystemExtPath, &entry) == 0;
+
+ void* iteration_cookie;
+ std::string name;
+
+ StartIteration(default_target.get(), &iteration_cookie, "IMAGES/", ".img");
+ for (int status = 0; status != -1; status = Next(iteration_cookie, &entry, &name)) {
+ if (name == "") {
+ continue;
+ }
+ LOG(INFO) << "Name is \"" << name << "\"";
+ if (name == kSystemPath) {
+ continue;
+ } else if (system_target_has_ext && name == kSystemExtPath) {
+ continue;
+ }
+ LOG(INFO) << "Writing " << name;
+ out_writer.StartEntry(name, 0);
+ ProcessZipEntryContents(
+ default_target.get(), &entry, CopyZipFileContents, (void*) &out_writer);
+ out_writer.FinishEntry();
+ }
+ EndIteration(iteration_cookie);
+
+ StartIteration(system_target.get(), &iteration_cookie, "IMAGES/", ".img");
+ for (int status = 0; status != -1; status = Next(iteration_cookie, &entry, &name)) {
+ bool is_system_image = name == kSystemPath;
+ bool is_system_ext_image = name == kSystemExtPath;
+ if (!is_system_image && !is_system_ext_image) {
+ continue;
+ }
+ LOG(INFO) << "Writing " << name;
+ out_writer.StartEntry(name, 0);
+ ProcessZipEntryContents(
+ system_target.get(), &entry, CopyZipFileContents, (void*) &out_writer);
+ out_writer.FinishEntry();
+ }
+ EndIteration(iteration_cookie);
+
+ int success = out_writer.Finish();
+ if (success != 0) {
+ LOG(ERROR) << "Unable to write combined image zip archive: " << success;
+ return false;
+ }
+
+ return true;
+}
+
+bool BuildSuperImage(const std::string& combined_target_zip,
+ const std::string& output_path) {
+ std::string build_super_image_binary;
+ std::string otatools_path;
+ if (FileExists(DefaultHostArtifactsPath("otatools/bin/build_super_image"))) {
+ build_super_image_binary =
+ DefaultHostArtifactsPath("otatools/bin/build_super_image");
+ otatools_path = DefaultHostArtifactsPath("otatools");
+ } else if (FileExists(DefaultHostArtifactsPath("bin/build_super_image"))) {
+ build_super_image_binary =
+ DefaultHostArtifactsPath("bin/build_super_image");
+ otatools_path = DefaultHostArtifactsPath("");
+ } else {
+ LOG(ERROR) << "Could not find otatools";
+ return false;
+ }
+ return cvd::execute({
+ build_super_image_binary,
+ "--path=" + otatools_path,
+ combined_target_zip,
+ output_path,
+ }) == 0;
+}
+
+} // namespace
+
+bool SuperImageNeedsRebuilding(const cvd::FetcherConfig& fetcher_config,
+ const vsoc::CuttlefishConfig&) {
+ bool has_default_build = false;
+ bool has_system_build = false;
+ for (const auto& file_iter : fetcher_config.get_cvd_files()) {
+ if (file_iter.second.source == cvd::FileSource::DEFAULT_BUILD) {
+ has_default_build = true;
+ } else if (file_iter.second.source == cvd::FileSource::SYSTEM_BUILD) {
+ has_system_build = true;
+ }
+ }
+ return has_default_build && has_system_build;
+}
+
+bool RebuildSuperImage(const cvd::FetcherConfig& fetcher_config,
+ const vsoc::CuttlefishConfig& config,
+ const std::string& output_path) {
+ std::string default_target_zip =
+ TargetFilesZip(fetcher_config, cvd::FileSource::DEFAULT_BUILD);
+ if (default_target_zip == "") {
+ LOG(ERROR) << "Unable to find default target zip file.";
+ return false;
+ }
+ std::string system_target_zip =
+ TargetFilesZip(fetcher_config, cvd::FileSource::SYSTEM_BUILD);
+ if (system_target_zip == "") {
+ LOG(ERROR) << "Unable to find system target zip file.";
+ return false;
+ }
+ std::string combined_target_zip = config.PerInstancePath("target_combined.zip");
+ // TODO(schuffelen): Use otatools/bin/merge_target_files
+ if (!CombineTargetZipFiles(default_target_zip, system_target_zip,
+ combined_target_zip)) {
+ LOG(ERROR) << "Could not combine target zip files.";
+ return false;
+ }
+ bool success = BuildSuperImage(combined_target_zip, output_path);
+ if (!success) {
+ LOG(ERROR) << "Could not write the final output super image.";
+ }
+ return success;
+}