Reimplement install_zip.sh in fetch_cvd.
Converts android sparse images to regular image files, and unsparses
image files.
Based on install_zip.sh here:
https://github.com/google/android-cuttlefish/blob/02da94513b6bb9dd534c4e54f81d49df5a050621/host/deploy/install_zip.sh
install_zip.sh also delegates to unpack_boot_imgage.py. This doesn't
seem immediately necessary to implement considering the launcher already
has an implementation that looks like a conversion of the script:
https://github.com/google/android-cuttlefish/blob/9e8ffef/host/deploy/unpack_boot_image.py
https://android.googlesource.com/device/google/cuttlefish_common/+/e13a78a/host/commands/launch/boot_image_unpacker.cc
Bug: 137304531
Test: ./fetch_cvd -run -- -daemon
Change-Id: I9dc35e9a5862a601abceea8634611e098fe301d4
diff --git a/host/commands/fetcher/Android.bp b/host/commands/fetcher/Android.bp
index 0c88171..4ab6178 100644
--- a/host/commands/fetcher/Android.bp
+++ b/host/commands/fetcher/Android.bp
@@ -19,6 +19,7 @@
"build_api.cc",
"credential_source.cc",
"curl_wrapper.cc",
+ "install_zip.cc",
"main.cc",
],
header_libs: [
@@ -29,6 +30,7 @@
"cuttlefish_auto_resources",
"libbase",
"libcuttlefish_fs",
+ "libcuttlefish_strings",
"libcuttlefish_utils",
"libcurl",
"libcrypto",
diff --git a/host/commands/fetcher/install_zip.cc b/host/commands/fetcher/install_zip.cc
new file mode 100644
index 0000000..ad7f08c
--- /dev/null
+++ b/host/commands/fetcher/install_zip.cc
@@ -0,0 +1,96 @@
+//
+// 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 "install_zip.h"
+
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+#include <glog/logging.h>
+
+#include "common/libs/strings/str_split.h"
+#include "common/libs/utils/subprocess.h"
+
+namespace {
+
+std::vector<std::string> ArchiveContents(const std::string& archive) {
+ std::string bsdtar_output;
+ auto bsdtar_ret =
+ cvd::execute_capture_output({"/usr/bin/bsdtar", "-tf", archive},
+ &bsdtar_output);
+ return bsdtar_ret == 0
+ ? cvd::StrSplit(bsdtar_output, '\n')
+ : std::vector<std::string>();
+}
+
+} // namespace
+
+bool ExtractImages(const std::string& archive,
+ const std::string& target_directory,
+ const std::vector<std::string>& images) {
+ std::vector<std::string> bsdtar_cmd = {
+ "/usr/bin/bsdtar",
+ "-x",
+ "-v",
+ "-C", target_directory,
+ "-f", archive,
+ "-S",
+ };
+ for (const auto& img : images) {
+ bsdtar_cmd.push_back(img);
+ }
+ auto bsdtar_ret = cvd::execute(bsdtar_cmd);
+ if (bsdtar_ret != 0) {
+ LOG(ERROR) << "Unable to extract images. bsdtar returned " << bsdtar_ret;
+ return false;
+ }
+
+ bool extraction_success = true;
+ std::vector<std::string> files =
+ images.size() > 0 ? images : ArchiveContents(archive);
+ for (const auto& file : files) {
+ if (file.find(".img") == std::string::npos) {
+ continue;
+ }
+ std::string extracted_file = target_directory + "/" + file;
+
+ std::string file_output;
+ auto file_ret = cvd::execute_capture_output(
+ {"/usr/bin/file", extracted_file}, &file_output);
+ if (file_ret != 0) {
+ LOG(ERROR) << "Unable to run file on " << file << ", returned" << file_ret;
+ extraction_success = false;
+ continue;
+ }
+ if (file_output.find("Android sparse image,") == std::string::npos) {
+ continue;
+ }
+ std::string inflated_file = extracted_file + ".inflated";
+ auto simg_ret = cvd::execute({"/usr/bin/simg2img", extracted_file, inflated_file});
+ if (simg_ret != 0) {
+ LOG(ERROR) << "Unable to run simg2img on " << file;
+ extraction_success = false;
+ continue;
+ }
+ auto rename_ret = rename(inflated_file.c_str(), extracted_file.c_str());
+ if (rename_ret != 0) {
+ LOG(ERROR) << "Unable to rename deflated version of " << file;
+ extraction_success = false;
+ }
+ }
+ return extraction_success;
+}
diff --git a/host/commands/fetcher/install_zip.h b/host/commands/fetcher/install_zip.h
new file mode 100644
index 0000000..0e36528
--- /dev/null
+++ b/host/commands/fetcher/install_zip.h
@@ -0,0 +1,23 @@
+//
+// 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.
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+bool ExtractImages(const std::string& archive,
+ const std::string& target_directory,
+ const std::vector<std::string>& images);
diff --git a/host/commands/fetcher/main.cc b/host/commands/fetcher/main.cc
index 3e555e5..d5c1cac 100644
--- a/host/commands/fetcher/main.cc
+++ b/host/commands/fetcher/main.cc
@@ -26,6 +26,7 @@
#include "build_api.h"
#include "credential_source.h"
+#include "install_zip.h"
// TODO(schuffelen): Mixed builds.
DEFINE_string(build_id, "latest", "Build ID for all artifacts");
@@ -72,18 +73,10 @@
std::string local_path = target_directory + "/" + img_zip_name;
build_api->ArtifactToFile(build_id, target, "latest",
img_zip_name, local_path);
- // -o for "overwrite"
- std::vector<std::string> command = {"/usr/bin/unzip", "-o", local_path,
- "-d", target_directory};
- for (const auto& image_file : images) {
- command.push_back(image_file);
- }
- int result = cvd::execute(command);
- if (result != 0) {
- LOG(ERROR) << "Could not extract " << local_path << "; ran command";
- for (const auto& argument : command) {
- LOG(ERROR) << argument;
- }
+
+ auto could_extract = ExtractImages(local_path, target_directory, images);
+ if (!could_extract) {
+ LOG(ERROR) << "Could not extract " << local_path;
return false;
}
if (unlink(local_path.c_str()) != 0) {
@@ -122,6 +115,15 @@
return true;
}
+bool desparse(const std::string& file) {
+ LOG(INFO) << "Unsparsing " << file;
+ if (cvd::execute({"/bin/dd", "if=" + file, "of=" + file, "conv=notrunc"}) != 0) {
+ LOG(ERROR) << "Could not unsparse " << file;
+ return false;
+ }
+ return true;
+}
+
} // namespace
int main(int argc, char** argv) {
@@ -156,6 +158,7 @@
LOG(FATAL) << "Could not download images with target "
<< FLAGS_target << " and build id " << build_id;
}
+ desparse(target_dir + "/userdata.img");
if (FLAGS_system_image_build_id != "") {
std::string system_target = FLAGS_system_image_build_target == ""
? FLAGS_target