Merge "SnapshotTest: update to match DeviceSnapshotHandler API change" into main
diff --git a/apex/com.google.cf.wifi/com.google.cf.wifi.rc b/apex/com.google.cf.wifi/com.google.cf.wifi.rc
index 11fbcf0..18d2f98 100644
--- a/apex/com.google.cf.wifi/com.google.cf.wifi.rc
+++ b/apex/com.google.cf.wifi/com.google.cf.wifi.rc
@@ -3,7 +3,7 @@
oneshot
# For legacy wifi without openwrt
-service setup_wifi /apex/com.google.cf.wifi/bin/setup_wifi
+service setup_wifi /apex/com.google.cf.wifi/bin/setup_wifi --interface=${ro.vendor.virtwifi.port}
user root
oneshot
diff --git a/common/libs/utils/files.cpp b/common/libs/utils/files.cpp
index 45828c3..095674a 100644
--- a/common/libs/utils/files.cpp
+++ b/common/libs/utils/files.cpp
@@ -82,6 +82,66 @@
return (follow_symlinks ? stat : lstat)(path.c_str(), &st) == 0;
}
+Result<dev_t> FileDeviceId(const std::string& path) {
+ struct stat out;
+ CF_EXPECTF(
+ stat(path.c_str(), &out) == 0,
+ "stat() failed trying to retrieve device ID information for \"{}\" "
+ "with error: {}",
+ path, strerror(errno));
+ return out.st_dev;
+}
+
+Result<bool> CanHardLink(const std::string& source,
+ const std::string& destination) {
+ return CF_EXPECT(FileDeviceId(source)) ==
+ CF_EXPECT(FileDeviceId(destination));
+}
+
+Result<ino_t> FileInodeNumber(const std::string& path) {
+ struct stat out;
+ CF_EXPECTF(
+ stat(path.c_str(), &out) == 0,
+ "stat() failed trying to retrieve inode num information for \"{}\" "
+ "with error: {}",
+ path, strerror(errno));
+ return out.st_ino;
+}
+
+Result<bool> AreHardLinked(const std::string& source,
+ const std::string& destination) {
+ return (CF_EXPECT(FileDeviceId(source)) ==
+ CF_EXPECT(FileDeviceId(destination))) &&
+ (CF_EXPECT(FileInodeNumber(source)) ==
+ CF_EXPECT(FileInodeNumber(destination)));
+}
+
+Result<std::string> CreateHardLink(const std::string& target,
+ const std::string& hardlink,
+ const bool overwrite_existing) {
+ if (FileExists(hardlink)) {
+ if (CF_EXPECT(AreHardLinked(target, hardlink))) {
+ return hardlink;
+ }
+ if (!overwrite_existing) {
+ return CF_ERRF(
+ "Cannot hardlink from \"{}\" to \"{}\", the second file already "
+ "exists and is not hardlinked to the first",
+ target, hardlink);
+ }
+ LOG(WARNING) << "Overwriting existing file \"" << hardlink << "\" with \""
+ << target << "\" from the cache";
+ CF_EXPECTF(unlink(hardlink.c_str()) == 0,
+ "Failed to unlink \"{}\" with error: {}", hardlink,
+ strerror(errno));
+ }
+ CF_EXPECTF(link(target.c_str(), hardlink.c_str()) == 0,
+ "link() failed trying to create hardlink from \"{}\" to \"{}\" "
+ "with error: {}",
+ target, hardlink, strerror(errno));
+ return hardlink;
+}
+
bool FileHasContent(const std::string& path) {
return FileSize(path) > 0;
}
diff --git a/common/libs/utils/files.h b/common/libs/utils/files.h
index 6e423cd..e47ad43 100644
--- a/common/libs/utils/files.h
+++ b/common/libs/utils/files.h
@@ -27,6 +27,15 @@
namespace cuttlefish {
bool FileExists(const std::string& path, bool follow_symlinks = true);
+Result<dev_t> FileDeviceId(const std::string& path);
+Result<bool> CanHardLink(const std::string& source,
+ const std::string& destination);
+Result<ino_t> FileInodeNumber(const std::string& path);
+Result<bool> AreHardLinked(const std::string& source,
+ const std::string& destination);
+Result<std::string> CreateHardLink(const std::string& target,
+ const std::string& hardlink,
+ const bool overwrite_existing = false);
bool FileHasContent(const std::string& path);
Result<std::vector<std::string>> DirectoryContents(const std::string& path);
bool DirectoryExists(const std::string& path, bool follow_symlinks = true);
diff --git a/guest/hals/vulkan/Android.bp b/guest/hals/vulkan/Android.bp
index 9e7b110..8d974da 100644
--- a/guest/hals/vulkan/Android.bp
+++ b/guest/hals/vulkan/Android.bp
@@ -34,7 +34,7 @@
"vulkan.pastel",
],
},
- }
+ },
}
apex {
@@ -58,6 +58,7 @@
"vulkan.ranchu",
],
prebuilts: [
+ "com.google.cf.vulkan.rc",
"com.google.cf.vulkan-linker-config",
"android.hardware.vulkan.level-1.prebuilt.xml",
"android.hardware.vulkan.compute-0.prebuilt.xml",
@@ -67,6 +68,12 @@
],
}
+prebuilt_etc {
+ name: "com.google.cf.vulkan.rc",
+ src: "com.google.cf.vulkan.rc",
+ installable: false,
+}
+
linker_config {
name: "com.google.cf.vulkan-linker-config",
src: "apex_linkerconfig.json",
diff --git a/guest/hals/vulkan/com.google.cf.vulkan.rc b/guest/hals/vulkan/com.google.cf.vulkan.rc
new file mode 100644
index 0000000..bd638cc
--- /dev/null
+++ b/guest/hals/vulkan/com.google.cf.vulkan.rc
@@ -0,0 +1,5 @@
+# `on init` is normally not available for .rc files in vendor apexes
+# But the vulkan apex is okay because it's bootstrap APEX.
+# For bootstrap APEXes, `on init` is the earliest available trigger.
+on init
+ setprop ro.vulkan.apex com.google.cf.vulkan
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index 0f73d4d..c386c3d 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -242,6 +242,7 @@
preserving.insert("persistent_composite_gpt_footer.img");
preserving.insert("persistent_composite.img");
preserving.insert("persistent_composite_overlay.img");
+ preserving.insert("pflash.img");
preserving.insert("uboot_env.img");
preserving.insert("factory_reset_protected.img");
preserving.insert("misc.img");
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index d7fac96..f7144f9 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -613,6 +613,20 @@
return {};
}
+Result<void> InitializePflash(
+ const CuttlefishConfig::InstanceSpecific& instance) {
+ if (FileExists(instance.pflash_path())) {
+ return {};
+ }
+
+ auto boot_size_mb = FileSize(instance.bootloader()) / (1 << 20);
+
+ // Pad out bootloader space to 4MB
+ CF_EXPECTF(CreateBlankImage(instance.pflash_path(), 4 - boot_size_mb, "none"),
+ "Failed to create '{}'", instance.pflash_path());
+ return {};
+}
+
Result<void> InitializeSdCard(
const CuttlefishConfig& config,
const CuttlefishConfig::InstanceSpecific& instance) {
@@ -693,7 +707,8 @@
.install(AutoSetup<GeneratePersistentBootconfig>::Component)
.install(AutoSetup<GeneratePersistentVbmeta>::Component)
.install(AutoSetup<InitializeInstanceCompositeDisk>::Component)
- .install(AutoSetup<InitializeDataImage>::Component);
+ .install(AutoSetup<InitializeDataImage>::Component)
+ .install(AutoSetup<InitializePflash>::Component);
}
Result<void> DiskImageFlagsVectorization(CuttlefishConfig& config, const FetcherConfig& fetcher_config) {
diff --git a/host/commands/assemble_cvd/misc_info.cc b/host/commands/assemble_cvd/misc_info.cc
index 292258b..2548a5e 100644
--- a/host/commands/assemble_cvd/misc_info.cc
+++ b/host/commands/assemble_cvd/misc_info.cc
@@ -16,22 +16,136 @@
#include "misc_info.h"
#include <algorithm>
+#include <array>
+#include <memory>
+#include <set>
#include <string>
+#include <string_view>
+#include <unordered_set>
#include <vector>
#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
+#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <fmt/format.h>
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/contains.h"
#include "common/libs/utils/result.h"
+#include "host/libs/avb/avb.h"
+#include "host/libs/config/known_paths.h"
namespace cuttlefish {
namespace {
+constexpr char kAvbVbmetaAlgorithm[] = "avb_vbmeta_algorithm";
+constexpr char kAvbVbmetaArgs[] = "avb_vbmeta_args";
+constexpr char kAvbVbmetaKeyPath[] = "avb_vbmeta_key_path";
constexpr char kDynamicPartitions[] = "dynamic_partition_list";
constexpr char kGoogleDynamicPartitions[] = "google_dynamic_partitions";
+constexpr char kRollbackIndexSuffix[] = "_rollback_index_location";
+constexpr char kSuperBlockDevices[] = "super_block_devices";
constexpr char kSuperPartitionGroups[] = "super_partition_groups";
+constexpr char kUseDynamicPartitions[] = "use_dynamic_partitions";
+constexpr char kRsa2048Algorithm[] = "SHA256_RSA2048";
+constexpr char kRsa4096Algorithm[] = "SHA256_RSA4096";
+constexpr std::array kNonPartitionKeysToMerge = {
+ "ab_update", "default_system_dev_certificate"};
+// based on build/make/tools/releasetools/common.py:AVB_PARTITIONS
+constexpr std::array kVbmetaPartitions = {"boot",
+ "init_boot",
+ "odm",
+ "odm_dlkm",
+ "vbmeta_system",
+ "vbmeta_system_dlkm",
+ "vbmeta_vendor_dlkm",
+ "vendor",
+ "vendor_boot"};
+
+Result<std::string> GetExpected(const MiscInfo& misc_info,
+ const std::string& key) {
+ auto lookup = misc_info.find(key);
+ CF_EXPECTF(lookup != misc_info.end(),
+ "Unable to retrieve expected value from key: {}", key);
+ return lookup->second;
+}
+
+std::string MergePartitionLists(const std::string& vendor,
+ const std::string& system,
+ const std::set<std::string>& extracted_images) {
+ const std::string full_string = fmt::format("{} {}", vendor, system);
+ const std::vector<std::string> full_list =
+ android::base::Tokenize(full_string, " ");
+ // std::set removes duplicates and orders the elements, which we want
+ const std::set<std::string> full_set(full_list.begin(), full_list.end());
+ std::set<std::string> filtered_set;
+ std::set_intersection(full_set.cbegin(), full_set.cend(),
+ extracted_images.cbegin(), extracted_images.cend(),
+ std::inserter(filtered_set, filtered_set.begin()));
+ return android::base::Join(filtered_set, " ");
+}
+
+std::string GetPartitionList(const MiscInfo& vendor_info,
+ const MiscInfo& system_info,
+ const std::string& key,
+ const std::set<std::string>& extracted_images) {
+ std::string vendor_list = GetExpected(vendor_info, key).value_or("");
+ std::string system_list = GetExpected(system_info, key).value_or("");
+ return MergePartitionLists(vendor_list, system_list, extracted_images);
+}
+
+std::vector<std::string> GeneratePartitionKeys(const std::string& name) {
+ std::vector<std::string> result;
+ result.emplace_back("avb_" + name);
+ result.emplace_back("avb_" + name + "_algorithm");
+ result.emplace_back("avb_" + name + "_key_path");
+ result.emplace_back("avb_" + name + kRollbackIndexSuffix);
+ result.emplace_back("avb_" + name + "_hashtree_enable");
+ result.emplace_back("avb_" + name + "_add_hashtree_footer_args");
+ result.emplace_back(name + "_disable_sparse");
+ result.emplace_back("building_" + name + "_image");
+ auto fs_type_key = name + "_fs_type";
+ if (name == "system") {
+ fs_type_key = "fs_type";
+ }
+ result.emplace_back(fs_type_key);
+ return result;
+}
+
+Result<int> ResolveRollbackIndexConflicts(
+ const std::string& index_string,
+ const std::unordered_set<int> used_indices) {
+ int index;
+ CF_EXPECTF(android::base::ParseInt(index_string, &index),
+ "Unable to parse value {} to string. Maybe a wrong or bad value "
+ "read for the rollback index?",
+ index_string);
+ while (Contains(used_indices, index)) {
+ ++index;
+ }
+ return index;
+}
+
+Result<std::string> GetKeyPath(const std::string_view algorithm) {
+ if (algorithm == kRsa4096Algorithm) {
+ return TestKeyRsa4096();
+ } else if (algorithm == kRsa2048Algorithm) {
+ return TestKeyRsa2048();
+ } else {
+ return CF_ERR("Unexpected algorithm. No key available.");
+ }
+}
+
+Result<std::string> GetPubKeyPath(const std::string_view algorithm) {
+ if (algorithm == kRsa4096Algorithm) {
+ return TestPubKeyRsa4096();
+ } else if (algorithm == kRsa2048Algorithm) {
+ return TestPubKeyRsa2048();
+ } else {
+ return CF_ERR("Unexpected algorithm. No key available.");
+ }
+}
} // namespace
@@ -61,73 +175,158 @@
return misc_info;
}
-std::string WriteMiscInfo(const MiscInfo& misc_info) {
- std::stringstream out;
+Result<void> WriteMiscInfo(const MiscInfo& misc_info,
+ const std::string& output_path) {
+ std::stringstream file_content;
for (const auto& entry : misc_info) {
- out << entry.first << "=" << entry.second << "\n";
+ file_content << entry.first << "=" << entry.second << "\n";
}
- return out.str();
+
+ SharedFD output_file = SharedFD::Creat(output_path.c_str(), 0644);
+ CF_EXPECT(output_file->IsOpen(),
+ "Failed to open output misc file: " << output_file->StrError());
+
+ CF_EXPECT(
+ WriteAll(output_file, file_content.str()) >= 0,
+ "Failed to write output misc file contents: " << output_file->StrError());
+ return {};
}
-std::vector<std::string> SuperPartitionComponents(const MiscInfo& info) {
- auto value_it = info.find(kDynamicPartitions);
- if (value_it == info.end()) {
- return {};
- }
- auto components = android::base::Split(value_it->second, " ");
- for (auto& component : components) {
- component = android::base::Trim(component);
- }
- components.erase(std::remove(components.begin(), components.end(), ""),
- components.end());
- return components;
-}
-
-bool SetSuperPartitionComponents(const std::vector<std::string>& components,
- MiscInfo* misc_info) {
- auto super_partition_groups = misc_info->find(kSuperPartitionGroups);
- if (super_partition_groups == misc_info->end()) {
- LOG(ERROR) << "Failed to find super partition groups in misc_info";
- return false;
- }
-
- // Remove all existing update groups in misc_info
- auto update_groups =
- android::base::Split(super_partition_groups->second, " ");
- for (const auto& group_name : update_groups) {
- auto partition_list = android::base::StringPrintf("super_%s_partition_list",
- group_name.c_str());
- auto partition_size =
- android::base::StringPrintf("super_%s_group_size", group_name.c_str());
- for (const auto& key : {partition_list, partition_size}) {
- auto it = misc_info->find(key);
- if (it == misc_info->end()) {
- LOG(ERROR) << "Failed to find " << key << " in misc_info";
- return false;
- }
- misc_info->erase(it);
+// based on build/make/tools/releasetools/merge/merge_target_files.py
+Result<MiscInfo> GetCombinedDynamicPartitions(
+ const MiscInfo& vendor_info, const MiscInfo& system_info,
+ const std::set<std::string>& extracted_images) {
+ auto vendor_use_dp =
+ CF_EXPECT(GetExpected(vendor_info, kUseDynamicPartitions));
+ CF_EXPECTF(vendor_use_dp == "true", "Vendor build must have {}=true",
+ kUseDynamicPartitions);
+ auto system_use_dp =
+ CF_EXPECT(GetExpected(system_info, kUseDynamicPartitions));
+ CF_EXPECTF(system_use_dp == "true", "System build must have {}=true",
+ kUseDynamicPartitions);
+ MiscInfo result;
+ // copy where both files are equal
+ for (const auto& key_val : vendor_info) {
+ const auto value_result = GetExpected(system_info, key_val.first);
+ if (value_result.ok() && *value_result == key_val.second) {
+ result[key_val.first] = key_val.second;
}
}
- // For merged target-file, put all dynamic partitions under the
- // google_dynamic_partitions update group.
- // TODO(xunchang) use different update groups for system and vendor images.
- (*misc_info)[kDynamicPartitions] = android::base::Join(components, " ");
- (*misc_info)[kSuperPartitionGroups] = kGoogleDynamicPartitions;
- std::string partitions_list_key = android::base::StringPrintf(
- "super_%s_partition_list", kGoogleDynamicPartitions);
- (*misc_info)[partitions_list_key] = android::base::Join(components, " ");
+ result[kDynamicPartitions] = GetPartitionList(
+ vendor_info, system_info, kDynamicPartitions, extracted_images);
- // Use the entire super partition as the group size
- std::string group_size_key = android::base::StringPrintf(
- "super_%s_group_size", kGoogleDynamicPartitions);
- auto super_size_it = misc_info->find("super_partition_size");
- if (super_size_it == misc_info->end()) {
- LOG(ERROR) << "Failed to find super partition size";
- return false;
+ const auto block_devices_result =
+ GetExpected(vendor_info, kSuperBlockDevices);
+ if (block_devices_result.ok()) {
+ result[kSuperBlockDevices] = *block_devices_result;
+ for (const auto& block_device :
+ android::base::Tokenize(result[kSuperBlockDevices], " ")) {
+ const auto key = "super_" + block_device + "_device_size";
+ result[key] = CF_EXPECT(GetExpected(vendor_info, key));
+ }
}
- (*misc_info)[group_size_key] = super_size_it->second;
- return true;
+
+ result[kSuperPartitionGroups] =
+ CF_EXPECT(GetExpected(vendor_info, kSuperPartitionGroups));
+ for (const auto& group :
+ android::base::Tokenize(result[kSuperPartitionGroups], " ")) {
+ const auto group_size_key = "super_" + group + "_group_size";
+ result[group_size_key] =
+ CF_EXPECT(GetExpected(vendor_info, group_size_key));
+
+ const auto partition_list_key = "super_" + group + "_partition_list";
+ result[partition_list_key] = GetPartitionList(
+ vendor_info, system_info, partition_list_key, extracted_images);
+ }
+
+ // TODO(chadreynolds): add vabc_cow_version logic if we need to support older
+ // builds
+ for (const auto& key :
+ {"virtual_ab", "virtual_ab_retrofit", "lpmake", "super_metadata_device",
+ "super_partition_error_limit", "super_partition_size"}) {
+ const auto value_result = GetExpected(vendor_info, key);
+ if (value_result.ok()) {
+ result[key] = *value_result;
+ }
+ }
+ return std::move(result);
+}
+
+Result<MiscInfo> MergeMiscInfos(
+ const MiscInfo& vendor_info, const MiscInfo& system_info,
+ const MiscInfo& combined_dp_info,
+ const std::vector<std::string>& system_partitions) {
+ // the combined misc info uses the vendor values as defaults
+ MiscInfo result = vendor_info;
+ std::unordered_set<int> used_indices;
+ for (const auto& partition : system_partitions) {
+ for (const auto& key : GeneratePartitionKeys(partition)) {
+ if (!Contains(system_info, key)) {
+ continue;
+ }
+ auto system_value = system_info.find(key)->second;
+ // avb_<partition>_rollback_index_location values can conflict across
+ // different builds
+ if (android::base::EndsWith(key, kRollbackIndexSuffix)) {
+ const auto index = CF_EXPECT(
+ ResolveRollbackIndexConflicts(system_value, used_indices));
+ used_indices.insert(index);
+ system_value = std::to_string(index);
+ }
+ result[key] = system_value;
+ }
+ }
+ for (const auto& key : kNonPartitionKeysToMerge) {
+ const auto value_result = GetExpected(system_info, key);
+ if (value_result.ok()) {
+ result[key] = *value_result;
+ }
+ }
+ for (const auto& key_val : combined_dp_info) {
+ result[key_val.first] = key_val.second;
+ }
+ return std::move(result);
+}
+
+Result<VbmetaArgs> GetVbmetaArgs(const MiscInfo& misc_info,
+ const std::string& image_path) {
+ // The key_path value should exist, but it is a build system path
+ // We use a host artifacts relative path instead
+ CF_EXPECT(Contains(misc_info, kAvbVbmetaKeyPath));
+ const auto algorithm = CF_EXPECT(GetExpected(misc_info, kAvbVbmetaAlgorithm));
+ auto result = VbmetaArgs{
+ .algorithm = algorithm,
+ .key_path = CF_EXPECT(GetKeyPath(algorithm)),
+ };
+ // must split and add --<flag> <arg> arguments(non-equals format) separately
+ // due to how Command.AddParameter handles each argument
+ const auto extra_args_result = GetExpected(misc_info, kAvbVbmetaArgs);
+ if (extra_args_result.ok()) {
+ for (const auto& arg : android::base::Tokenize(*extra_args_result, " ")) {
+ result.extra_arguments.emplace_back(arg);
+ }
+ }
+
+ for (const auto& partition : kVbmetaPartitions) {
+ // The key_path value should exist, but it is a build system path
+ // We use a host artifacts relative path instead
+ if (Contains(misc_info, fmt::format("avb_{}_key_path", partition))) {
+ const auto partition_algorithm = CF_EXPECT(
+ GetExpected(misc_info, fmt::format("avb_{}_algorithm", partition)));
+ result.chained_partitions.emplace_back(ChainPartition{
+ .name = partition,
+ .rollback_index = CF_EXPECT(GetExpected(
+ misc_info,
+ fmt::format("avb_{}_rollback_index_location", partition))),
+ .key_path = CF_EXPECT(GetPubKeyPath(partition_algorithm)),
+ });
+ } else {
+ result.included_partitions.emplace_back(
+ fmt::format("{}/IMAGES/{}.img", image_path, partition));
+ }
+ }
+ return result;
}
} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/misc_info.h b/host/commands/assemble_cvd/misc_info.h
index f832a4c..731a5ba 100644
--- a/host/commands/assemble_cvd/misc_info.h
+++ b/host/commands/assemble_cvd/misc_info.h
@@ -16,20 +16,37 @@
#pragma once
#include <map>
+#include <set>
#include <string>
-#include <vector>
#include "common/libs/utils/result.h"
+#include "host/libs/avb/avb.h"
namespace cuttlefish {
+// TODO(chadreynolds): rename MiscInfo to more generic KeyValueFile since this
+// logic is processing multiple filetypes now
using MiscInfo = std::map<std::string, std::string>;
-Result<MiscInfo> ParseMiscInfo(const std::string& file_contents);
-std::string WriteMiscInfo(const MiscInfo& info);
+struct VbmetaArgs {
+ std::string algorithm;
+ std::string key_path;
+ std::vector<ChainPartition> chained_partitions;
+ std::vector<std::string> included_partitions;
+ std::vector<std::string> extra_arguments;
+};
-std::vector<std::string> SuperPartitionComponents(const MiscInfo&);
-bool SetSuperPartitionComponents(const std::vector<std::string>& components,
- MiscInfo* misc_info);
+Result<MiscInfo> ParseMiscInfo(const std::string& file_contents);
+Result<void> WriteMiscInfo(const MiscInfo& misc_info,
+ const std::string& output_path);
+Result<MiscInfo> GetCombinedDynamicPartitions(
+ const MiscInfo& vendor_info, const MiscInfo& system_info,
+ const std::set<std::string>& extracted_images);
+Result<MiscInfo> MergeMiscInfos(
+ const MiscInfo& vendor_info, const MiscInfo& system_info,
+ const MiscInfo& combined_dp_info,
+ const std::vector<std::string>& system_partitions);
+Result<VbmetaArgs> GetVbmetaArgs(const MiscInfo& misc_info,
+ const std::string& image_path);
} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/super_image_mixer.cc b/host/commands/assemble_cvd/super_image_mixer.cc
index b59d163..ee23244 100644
--- a/host/commands/assemble_cvd/super_image_mixer.cc
+++ b/host/commands/assemble_cvd/super_image_mixer.cc
@@ -21,42 +21,40 @@
#include <array>
#include <memory>
#include <string>
+#include <string_view>
#include <unordered_set>
+#include <utility>
+#include <vector>
#include <android-base/strings.h>
#include <android-base/logging.h>
-#include "common/libs/fs/shared_buf.h"
#include "common/libs/utils/archive.h"
#include "common/libs/utils/contains.h"
#include "common/libs/utils/files.h"
#include "common/libs/utils/result.h"
#include "common/libs/utils/subprocess.h"
#include "host/commands/assemble_cvd/misc_info.h"
+#include "host/libs/avb/avb.h"
#include "host/libs/config/config_utils.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/config/fetcher_config.h"
+#include "host/libs/config/known_paths.h"
namespace cuttlefish {
namespace {
constexpr char kMiscInfoPath[] = "META/misc_info.txt";
+constexpr char kDynamicPartitionsPath[] = "META/dynamic_partitions_info.txt";
constexpr std::array kVendorTargetImages = {
- "IMAGES/boot.img",
- "IMAGES/dtbo.img",
- "IMAGES/init_boot.img",
- "IMAGES/odm.img",
- "IMAGES/odm_dlkm.img",
- "IMAGES/recovery.img",
- "IMAGES/system_dlkm.img",
- "IMAGES/userdata.img",
- "IMAGES/vbmeta.img",
- "IMAGES/vbmeta_system_dlkm.img",
- "IMAGES/vbmeta_vendor.img",
- "IMAGES/vbmeta_vendor_dlkm.img",
- "IMAGES/vendor.img",
- "IMAGES/vendor_dlkm.img",
- "IMAGES/vendor_kernel_boot.img",
+ "IMAGES/boot.img", "IMAGES/dtbo.img",
+ "IMAGES/init_boot.img", "IMAGES/odm.img",
+ "IMAGES/odm_dlkm.img", "IMAGES/recovery.img",
+ "IMAGES/system_dlkm.img", "IMAGES/userdata.img",
+ "IMAGES/vbmeta.img", "IMAGES/vbmeta_system_dlkm.img",
+ "IMAGES/vbmeta_vendor.img", "IMAGES/vbmeta_vendor_dlkm.img",
+ "IMAGES/vendor.img", "IMAGES/vendor_boot.img",
+ "IMAGES/vendor_dlkm.img", "IMAGES/vendor_kernel_boot.img",
};
constexpr std::array kVendorTargetBuildProps = {
"ODM/build.prop",
@@ -72,6 +70,11 @@
std::vector<std::string> system_contents;
};
+struct Extracted {
+ std::set<std::string> images;
+ std::vector<std::string> system_partitions;
+};
+
void FindImports(Archive* archive, const std::string& build_prop_file) {
auto contents = archive->ExtractToMemory(build_prop_file);
auto lines = android::base::Split(contents, "\n");
@@ -92,6 +95,17 @@
return android::base::EndsWith(filename, "build.prop");
}
+Result<std::string> GetPartitionNameFromPath(const std::string& path) {
+ std::string_view result(path);
+ CF_EXPECTF(
+ android::base::ConsumePrefix(&result, "IMAGES/"),
+ "target_files filepath {} expected to be in the \"IMAGES\" directory",
+ path);
+ CF_EXPECTF(android::base::ConsumeSuffix(&result, ".img"),
+ "target_files filepath {} expected to be a \".img\" file", path);
+ return std::string(result);
+}
+
Result<TargetFiles> GetTargetFiles(const std::string& vendor_zip_path,
const std::string& system_zip_path) {
auto result = TargetFiles{
@@ -107,42 +121,50 @@
return result;
}
-Result<void> CombineMiscInfo(TargetFiles& target_files,
- const std::string& misc_output_path) {
+Result<MiscInfo> CombineDynamicPartitionsInfo(
+ TargetFiles& target_files, const std::set<std::string>& extracted_images) {
+ CF_EXPECTF(Contains(target_files.vendor_contents, kDynamicPartitionsPath),
+ "Vendor target files zip does not contain {}",
+ kDynamicPartitionsPath);
+ CF_EXPECTF(Contains(target_files.system_contents, kDynamicPartitionsPath),
+ "System target files zip does not contain {}",
+ kDynamicPartitionsPath);
+
+ const MiscInfo vendor_dp_info = CF_EXPECT(ParseMiscInfo(
+ target_files.vendor_zip.ExtractToMemory(kDynamicPartitionsPath)));
+ const MiscInfo system_dp_info = CF_EXPECT(ParseMiscInfo(
+ target_files.system_zip.ExtractToMemory(kDynamicPartitionsPath)));
+
+ return CF_EXPECT(GetCombinedDynamicPartitions(vendor_dp_info, system_dp_info,
+ extracted_images));
+}
+
+Result<MiscInfo> CombineMiscInfo(
+ TargetFiles& target_files, const std::string& misc_output_path,
+ const std::set<std::string>& extracted_images,
+ const std::vector<std::string>& system_partitions) {
CF_EXPECTF(Contains(target_files.vendor_contents, kMiscInfoPath),
- "Default target files zip does not contain {}", kMiscInfoPath);
+ "Vendor target files zip does not contain {}", kMiscInfoPath);
CF_EXPECTF(Contains(target_files.system_contents, kMiscInfoPath),
"System target files zip does not contain {}", kMiscInfoPath);
- const MiscInfo default_misc = CF_EXPECT(
+ const MiscInfo vendor_misc = CF_EXPECT(
ParseMiscInfo(target_files.vendor_zip.ExtractToMemory(kMiscInfoPath)));
const MiscInfo system_misc = CF_EXPECT(
ParseMiscInfo(target_files.system_zip.ExtractToMemory(kMiscInfoPath)));
- auto output_misc = default_misc;
- auto system_super_partitions = SuperPartitionComponents(system_misc);
- // Ensure specific skipped partitions end up in the misc_info.txt
- for (auto partition :
- {"odm", "odm_dlkm", "vendor", "vendor_dlkm", "system_dlkm"}) {
- if (!Contains(system_super_partitions, partition)) {
- system_super_partitions.push_back(partition);
- }
- }
- CF_EXPECT(SetSuperPartitionComponents(system_super_partitions, &output_misc),
- "Failed to update super partitions components for misc_info");
+ const auto combined_dp_info =
+ CF_EXPECT(CombineDynamicPartitionsInfo(target_files, extracted_images));
+ const auto output_misc = CF_EXPECT(MergeMiscInfos(
+ vendor_misc, system_misc, combined_dp_info, system_partitions));
- SharedFD misc_output_file = SharedFD::Creat(misc_output_path.c_str(), 0644);
- CF_EXPECT(misc_output_file->IsOpen(), "Failed to open output misc file: "
- << misc_output_file->StrError());
-
- CF_EXPECT(WriteAll(misc_output_file, WriteMiscInfo(output_misc)) >= 0,
- "Failed to write output misc file contents: "
- << misc_output_file->StrError());
- return {};
+ CF_EXPECT(WriteMiscInfo(output_misc, misc_output_path));
+ return std::move(output_misc);
}
-Result<void> ExtractTargetFiles(TargetFiles& target_files,
- const std::string& combined_output_path) {
+Result<Extracted> ExtractTargetFiles(TargetFiles& target_files,
+ const std::string& combined_output_path) {
+ Extracted extracted;
for (const auto& name : target_files.vendor_contents) {
if (!IsTargetFilesImage(name)) {
continue;
@@ -153,6 +175,7 @@
CF_EXPECT(
target_files.vendor_zip.ExtractFiles({name}, combined_output_path),
"Failed to extract " << name << " from the vendor target zip");
+ extracted.images.emplace(CF_EXPECT(GetPartitionNameFromPath(name)));
}
for (const auto& name : target_files.vendor_contents) {
if (!IsTargetFilesBuildProp(name)) {
@@ -177,6 +200,9 @@
CF_EXPECT(
target_files.system_zip.ExtractFiles({name}, combined_output_path),
"Failed to extract " << name << " from the system target zip");
+ const auto partition = CF_EXPECT(GetPartitionNameFromPath(name));
+ extracted.images.emplace(partition);
+ extracted.system_partitions.emplace_back(partition);
}
for (const auto& name : target_files.system_contents) {
if (!IsTargetFilesBuildProp(name)) {
@@ -190,19 +216,36 @@
target_files.system_zip.ExtractFiles({name}, combined_output_path),
"Failed to extract " << name << " from the system target zip");
}
+ return extracted;
+}
+
+Result<void> RegenerateVbmeta(const MiscInfo& misc_info,
+ const std::string& output_path,
+ const std::string& image_path) {
+ const VbmetaArgs args = CF_EXPECT(GetVbmetaArgs(misc_info, image_path));
+ auto avbtool = Avb(AvbToolBinary(), args.algorithm, args.key_path);
+ CF_EXPECT(avbtool.MakeVbMetaImage(output_path, args.chained_partitions,
+ args.included_partitions,
+ args.extra_arguments));
return {};
}
Result<void> CombineTargetZipFiles(const std::string& vendor_zip_path,
const std::string& system_zip_path,
- const std::string& output_path) {
- CF_EXPECT(EnsureDirectoryExists(output_path));
- CF_EXPECT(EnsureDirectoryExists(output_path + "/META"));
+ const std::string& combined_target_path,
+ const std::string& vbmeta_output_path) {
+ CF_EXPECT(EnsureDirectoryExists(combined_target_path));
+ CF_EXPECT(EnsureDirectoryExists(combined_target_path + "/META"));
auto target_files =
CF_EXPECT(GetTargetFiles(vendor_zip_path, system_zip_path));
- CF_EXPECT(ExtractTargetFiles(target_files, output_path));
- const auto misc_output_path = output_path + "/" + kMiscInfoPath;
- CF_EXPECT(CombineMiscInfo(target_files, misc_output_path));
+ const auto extracted =
+ CF_EXPECT(ExtractTargetFiles(target_files, combined_target_path));
+ const auto misc_output_path = combined_target_path + "/" + kMiscInfoPath;
+ const auto combined_info =
+ CF_EXPECT(CombineMiscInfo(target_files, misc_output_path,
+ extracted.images, extracted.system_partitions));
+ CF_EXPECT(RegenerateVbmeta(combined_info, vbmeta_output_path,
+ combined_target_path));
return {};
}
@@ -240,7 +283,8 @@
Result<void> RebuildSuperImage(const FetcherConfig& fetcher_config,
const CuttlefishConfig& config,
- const std::string& output_path) {
+ const std::string& super_image_output,
+ const std::string& vbmeta_image_output) {
auto instance = config.ForDefaultInstance();
// In SuperImageNeedsRebuilding, it already checked both
// has_default_target_zip and has_system_target_zip are the same.
@@ -262,10 +306,10 @@
std::string combined_target_path = instance.PerInstanceInternalPath("target_combined");
// TODO(schuffelen): Use otatools/bin/merge_target_files
CF_EXPECT(CombineTargetZipFiles(default_target_zip, system_target_zip,
- combined_target_path),
+ combined_target_path, vbmeta_image_output),
"Could not combine target zip files.");
- CF_EXPECT(BuildSuperImage(combined_target_path, output_path),
+ CF_EXPECT(BuildSuperImage(combined_target_path, super_image_output),
"Could not write the final output super image.");
return {};
}
@@ -287,7 +331,8 @@
instance_.default_target_zip(),
instance_.system_target_zip()))) {
CF_EXPECT(RebuildSuperImage(fetcher_config_, config_,
- instance_.new_super_image()));
+ instance_.new_super_image(),
+ instance_.new_vbmeta_image()));
}
return {};
}
diff --git a/host/commands/control_env_proxy_server/Android.bp b/host/commands/control_env_proxy_server/Android.bp
index 0494145..0783d31 100644
--- a/host/commands/control_env_proxy_server/Android.bp
+++ b/host/commands/control_env_proxy_server/Android.bp
@@ -56,7 +56,6 @@
static_libs: [
"grpc_cli_libs",
"libabsl_host",
- "libc++fs",
"libcuttlefish_control_env",
"libcuttlefish_host_config",
"libgflags",
diff --git a/host/commands/cvd_env/Android.bp b/host/commands/cvd_env/Android.bp
index 58c4852..885088d 100644
--- a/host/commands/cvd_env/Android.bp
+++ b/host/commands/cvd_env/Android.bp
@@ -32,7 +32,6 @@
static_libs: [
"grpc_cli_libs",
"libabsl_host",
- "libc++fs",
"libcuttlefish_control_env",
"libcuttlefish_host_config",
"libgflags",
@@ -40,7 +39,6 @@
cflags: [
"-Wno-unused-parameter",
],
- cpp_std: "c++17",
defaults: ["cuttlefish_host"],
target: {
darwin: {
diff --git a/host/commands/modem_simulator/Android.bp b/host/commands/modem_simulator/Android.bp
index 0f684e8..9dec221 100644
--- a/host/commands/modem_simulator/Android.bp
+++ b/host/commands/modem_simulator/Android.bp
@@ -118,7 +118,4 @@
"device/google/cuttlefish/host/commands",
],
defaults: ["cuttlefish_host", "modem_simulator_base"],
- whole_static_libs: [
- "libc++fs"
- ],
}
diff --git a/host/commands/run_cvd/boot_state_machine.cc b/host/commands/run_cvd/boot_state_machine.cc
index fd858a4..e78aac0 100644
--- a/host/commands/run_cvd/boot_state_machine.cc
+++ b/host/commands/run_cvd/boot_state_machine.cc
@@ -176,6 +176,11 @@
if (boot_event_handler_.joinable()) {
boot_event_handler_.join();
}
+ if (restore_complete_stop_write_->IsOpen()) {
+ char c = 1;
+ CHECK_EQ(restore_complete_stop_write_->Write(&c, 1), 1)
+ << restore_complete_stop_write_->StrError();
+ }
if (restore_complete_handler_.joinable()) {
restore_complete_handler_.join();
}
@@ -208,19 +213,29 @@
CF_EXPECTF(boot_events_pipe->IsOpen(), "Could not get boot events pipe: {}",
boot_events_pipe->StrError());
+ // Pipe to tell `ThreadLoop` that the restore is complete.
SharedFD restore_complete_pipe, restore_complete_pipe_write;
+ // Pipe to tell `restore_complete_handler_` thread to give up.
+ // It isn't perfect, can only break out of the `WaitForRestoreComplete`
+ // step.
+ SharedFD restore_complete_stop_read;
if (IsRestoring(config_)) {
CF_EXPECT(
SharedFD::Pipe(&restore_complete_pipe, &restore_complete_pipe_write),
"unable to create pipe");
+ CF_EXPECT(SharedFD::Pipe(&restore_complete_stop_read,
+ &restore_complete_stop_write_),
+ "unable to create pipe");
- // Unlike `boot_event_handler_`, this doesn't support graceful shutdown,
- // it blocks until it finishes its work.
- restore_complete_handler_ =
- std::thread([this, restore_complete_pipe_write]() {
- const auto result = vm_manager_.WaitForRestoreComplete();
+ restore_complete_handler_ = std::thread(
+ [this, restore_complete_pipe_write, restore_complete_stop_read]() {
+ const auto result =
+ vm_manager_.WaitForRestoreComplete(restore_complete_stop_read);
CHECK(result.ok()) << "Failed to wait for restore complete: "
<< result.error().FormatForEnv();
+ if (!result.value()) {
+ return;
+ }
cuttlefish::SharedFD restore_adbd_pipe = cuttlefish::SharedFD::Open(
config_.ForDefaultInstance().restore_adbd_pipe_name().c_str(),
@@ -404,6 +419,7 @@
std::thread boot_event_handler_;
std::thread restore_complete_handler_;
+ SharedFD restore_complete_stop_write_;
SharedFD fg_launcher_pipe_;
SharedFD reboot_notification_;
SharedFD interrupt_fd_read_;
diff --git a/host/commands/run_cvd/server_loop_impl_snapshot.cpp b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
index c90c4ac..44539d6 100644
--- a/host/commands/run_cvd/server_loop_impl_snapshot.cpp
+++ b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
@@ -144,19 +144,31 @@
}
}
+static Result<void> RunAdbShellCommand(
+ const CuttlefishConfig::InstanceSpecific& ins,
+ const std::vector<std::string>& command_args) {
+ Command adb_command(SubtoolPath("adb"));
+ // Avoid the adb server being started in the runtime directory and looking
+ // like a process that is still using the directory.
+ adb_command.SetWorkingDirectory("/");
+ adb_command.AddParameter("-s").AddParameter(ins.adb_ip_and_port());
+ adb_command.AddParameter("wait-for-device");
+
+ adb_command.AddParameter("shell").AddParameter("cmd");
+ for (const auto& argument : command_args) {
+ adb_command.AddParameter(argument);
+ }
+ CF_EXPECT_EQ(adb_command.Start().Wait(), 0);
+ return {};
+}
+
Result<void> ServerLoopImpl::HandleSuspend(ProcessMonitor& process_monitor) {
// right order: guest -> host
LOG(DEBUG) << "Suspending the guest..";
- const auto adb_bin_path = SubtoolPath("adb");
- CF_EXPECT(Execute({adb_bin_path, "-s", instance_.adb_ip_and_port(), "shell",
- "cmd", "bluetooth_manager", "disable"},
- SubprocessOptions(), WEXITED));
- CF_EXPECT(Execute({adb_bin_path, "-s", instance_.adb_ip_and_port(), "shell",
- "cmd", "bluetooth_manager", "wait-for-state:STATE_OFF"},
- SubprocessOptions(), WEXITED));
- CF_EXPECT(Execute({adb_bin_path, "-s", instance_.adb_ip_and_port(), "shell",
- "cmd", "uwb", "disable-uwb"},
- SubprocessOptions(), WEXITED));
+ CF_EXPECT(RunAdbShellCommand(instance_, {"bluetooth_manager", "disable"}));
+ CF_EXPECT(RunAdbShellCommand(
+ instance_, {"bluetooth_manager", "wait-for-state:STATE_OFF"}));
+ CF_EXPECT(RunAdbShellCommand(instance_, {"uwb", "disable-uwb"}));
// right order: guest -> host
CF_EXPECT(SuspendGuest());
LOG(DEBUG) << "The guest is suspended.";
@@ -174,13 +186,8 @@
LOG(DEBUG) << "Resuming the guest..";
CF_EXPECT(ResumeGuest());
// Resume services after guest has resumed.
- const auto adb_bin_path = SubtoolPath("adb");
- CF_EXPECT(Execute({adb_bin_path, "-s", instance_.adb_ip_and_port(), "shell",
- "cmd", "bluetooth_manager", "enable"},
- SubprocessOptions(), WEXITED));
- CF_EXPECT(Execute({adb_bin_path, "-s", instance_.adb_ip_and_port(), "shell",
- "cmd", "uwb", "enable-uwb"},
- SubprocessOptions(), WEXITED));
+ CF_EXPECT(RunAdbShellCommand(instance_, {"bluetooth_manager", "enable"}));
+ CF_EXPECT(RunAdbShellCommand(instance_, {"uwb", "enable-uwb"}));
LOG(DEBUG) << "The guest resumed.";
return {};
}
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index dfa38cb..f23148d 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -394,6 +394,8 @@
std::string pstore_path() const;
+ std::string pflash_path() const;
+
std::string console_path() const;
std::string logcat_path() const;
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index de063a8..2bc2a3a 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -1277,6 +1277,10 @@
return AbsolutePath(PerInstancePath("pstore"));
}
+std::string CuttlefishConfig::InstanceSpecific::pflash_path() const {
+ return AbsolutePath(PerInstancePath("pflash.img"));
+}
+
std::string CuttlefishConfig::InstanceSpecific::console_path() const {
return AbsolutePath(PerInstancePath("console"));
}
diff --git a/host/libs/control_env/Android.bp b/host/libs/control_env/Android.bp
index 3c33d82..5b5264f 100644
--- a/host/libs/control_env/Android.bp
+++ b/host/libs/control_env/Android.bp
@@ -32,13 +32,11 @@
static_libs: [
"grpc_cli_libs",
"libabsl_host",
- "libc++fs",
"libgflags",
],
cflags: [
"-Wno-unused-parameter",
],
- cpp_std: "c++17",
defaults: ["cuttlefish_buildhost_only"],
target: {
darwin: {
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 3eb5118..d5475b6 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -16,6 +16,7 @@
#include "host/libs/vm_manager/crosvm_manager.h"
+#include <poll.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -816,6 +817,10 @@
":shared:type=fs");
}
+ if (instance.target_arch() == Arch::X86_64) {
+ crosvm_cmd.Cmd().AddParameter("--pflash=", instance.pflash_path());
+ }
+
// This needs to be the last parameter
crosvm_cmd.Cmd().AddParameter("--bios=", instance.bootloader());
@@ -890,14 +895,21 @@
return commands;
}
-Result<void> CrosvmManager::WaitForRestoreComplete() const {
+Result<bool> CrosvmManager::WaitForRestoreComplete(SharedFD stop_fd) const {
auto instance = CF_EXPECT(CuttlefishConfig::Get())->ForDefaultInstance();
// Wait for the control socket to exist. It is created early in crosvm's
// startup sequence, but the process may not even have been exec'd by CF at
// this point.
while (!FileExists(instance.CrosvmSocketPath())) {
- usleep(50000); // 50 ms, arbitrarily chosen
+ std::vector<PollSharedFd> poll = {{.fd = stop_fd, .events = POLLIN}};
+ const int result = SharedFD::Poll(poll, 50 /* ms */);
+ // Check for errors.
+ CF_EXPECT(result >= 0, "failed to wait on stop_fd: " << strerror(errno));
+ // Check if pipe became readable or closed.
+ if (result > 0) {
+ return false;
+ }
}
// Ask crosvm to resume the VM. crosvm promises to not complete this command
@@ -914,7 +926,7 @@
CF_EXPECT_EQ(infop.si_code, CLD_EXITED);
CF_EXPECTF(infop.si_status == 0, "crosvm resume returns non zero code {}",
infop.si_status);
- return {};
+ return true;
}
} // namespace vm_manager
diff --git a/host/libs/vm_manager/crosvm_manager.h b/host/libs/vm_manager/crosvm_manager.h
index cb119fe..6e26c05 100644
--- a/host/libs/vm_manager/crosvm_manager.h
+++ b/host/libs/vm_manager/crosvm_manager.h
@@ -46,7 +46,7 @@
const CuttlefishConfig& config,
std::vector<VmmDependencyCommand*>& dependencyCommands) override;
- Result<void> WaitForRestoreComplete() const override;
+ Result<bool> WaitForRestoreComplete(SharedFD stop_fd) const override;
private:
static constexpr int kCrosvmVmResetExitCode = 32;
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index ffd431d..2da484a 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -802,10 +802,17 @@
if (is_riscv64) {
qemu_cmd.AddParameter("-kernel");
- } else {
+ qemu_cmd.AddParameter(instance.bootloader());
+ } else if (is_arm) {
qemu_cmd.AddParameter("-bios");
+ qemu_cmd.AddParameter(instance.bootloader());
+ } else {
+ qemu_cmd.AddParameter("-drive");
+ qemu_cmd.AddParameter("if=pflash,format=raw,readonly=on,file=",
+ instance.bootloader());
+ qemu_cmd.AddParameter("-drive");
+ qemu_cmd.AddParameter("if=pflash,format=raw,file=", instance.pflash_path());
}
- qemu_cmd.AddParameter(instance.bootloader());
if (instance.gdb_port() > 0) {
qemu_cmd.AddParameter("-S");
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 9b70477..fe66824 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -107,8 +107,10 @@
// Block until the restore work is finished and the guest is running. Only
// called if a snapshot is being restored.
//
+ // If FD becomes readable or closed, gives up and returns false.
+ //
// Must be thread safe.
- virtual Result<void> WaitForRestoreComplete() const {
+ virtual Result<bool> WaitForRestoreComplete(SharedFD) const {
return CF_ERR("not implemented");
}
};
diff --git a/shared/BoardConfig.mk b/shared/BoardConfig.mk
index 004372f..c5accd1 100644
--- a/shared/BoardConfig.mk
+++ b/shared/BoardConfig.mk
@@ -18,10 +18,14 @@
# Common BoardConfig for all supported architectures.
#
-# Wear 32 bit is currently supported and 6.6 kernels don't support
-# 32 bit devices
+# Some targets still require 32 bit, and 6.6 kernels don't support
+# 32 bit devices (Wear, Go, Auto)
ifneq (,$(findstring gwear_x86,$(PRODUCT_NAME)))
TARGET_KERNEL_USE ?= 6.1
+else ifneq (,$(findstring x86_phone,$(PRODUCT_NAME)))
+TARGET_KERNEL_USE ?= 6.1
+else ifneq (,$(findstring x86_tv,$(PRODUCT_NAME)))
+TARGET_KERNEL_USE ?= 6.1
else
TARGET_KERNEL_USE ?= 6.6
endif
diff --git a/shared/config/input/Android.bp b/shared/config/input/Android.bp
index 7db65df..544e31c 100644
--- a/shared/config/input/Android.bp
+++ b/shared/config/input/Android.bp
@@ -26,6 +26,9 @@
// Install the apex in /vendor/apex
soc_specific: true,
prebuilts: [
+ // Set input_device.config_file.apex={apexname} sysprop
+ "com.google.cf.input.config.rc",
+ // Configs
"Crosvm_Virtio_Multitouch_Touchpad_0.idc",
"Crosvm_Virtio_Multitouch_Touchscreen_0.idc",
"Crosvm_Virtio_Multitouch_Touchscreen_1.idc",
@@ -35,6 +38,12 @@
],
}
+prebuilt_etc {
+ name: "com.google.cf.input.config.rc",
+ src: "com.google.cf.input.config.rc",
+ installable: false,
+}
+
prebuilt_defaults {
name: "crosvm_idc_defaults",
relative_install_path: "usr/idc",
diff --git a/shared/config/input/com.google.cf.input.config.rc b/shared/config/input/com.google.cf.input.config.rc
new file mode 100644
index 0000000..917c3fb
--- /dev/null
+++ b/shared/config/input/com.google.cf.input.config.rc
@@ -0,0 +1,2 @@
+on property:apex.all.ready=true
+ setprop input_device.config_file.apex com.google.cf.input.config
diff --git a/shared/config/input/file_contexts b/shared/config/input/file_contexts
index e982bd5..3f8e059 100644
--- a/shared/config/input/file_contexts
+++ b/shared/config/input/file_contexts
@@ -1,4 +1,5 @@
(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
/etc/usr/keylayout(/.*)?\.kl u:object_r:vendor_keylayout_file:s0
/etc/usr/keychars(/.*)?\.kcm u:object_r:vendor_keychars_file:s0
/etc/usr/idc(/.*)?\.idc u:object_r:vendor_idc_file:s0
diff --git a/shared/device.mk b/shared/device.mk
index 34d87ea..ae77f41 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -218,6 +218,8 @@
endif
DEVICE_MANIFEST_FILE += $(LOCAL_DEVICE_FCM_MANIFEST_FILE)
+PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := true
+
#
# General files
#
@@ -258,7 +260,6 @@
# Install .kcm/.kl/.idc files via input.config apex
#
PRODUCT_PACKAGES += com.google.cf.input.config
-PRODUCT_VENDOR_PROPERTIES += input_device.config_file.apex=com.google.cf.input.config
PRODUCT_PACKAGES += \
fstab.cf.f2fs.hctr2 \
diff --git a/shared/graphics/device_vendor.mk b/shared/graphics/device_vendor.mk
index 2d01146..d13904d 100644
--- a/shared/graphics/device_vendor.mk
+++ b/shared/graphics/device_vendor.mk
@@ -45,7 +45,6 @@
# Gfxstream Vulkan implementation (Vulkan streamed to the host).
ifeq ($(TARGET_VULKAN_SUPPORT),true)
PRODUCT_PACKAGES += com.google.cf.vulkan
-PRODUCT_VENDOR_PROPERTIES += ro.vulkan.apex=com.google.cf.vulkan
endif
#
diff --git a/shared/sepolicy/system_ext/private/platform_app.te b/shared/sepolicy/system_ext/private/platform_app.te
index 3a789d8..fc1b99f 100644
--- a/shared/sepolicy/system_ext/private/platform_app.te
+++ b/shared/sepolicy/system_ext/private/platform_app.te
@@ -2,3 +2,6 @@
# allow systemui to set boot animation colors
set_prop(platform_app, bootanim_system_prop);
+
+# allow platform_app/systemui access to fingerprint
+hal_client_domain(platform_app, hal_fingerprint)
diff --git a/shared/tv/device_vendor.mk b/shared/tv/device_vendor.mk
index f6e10ab..6b1de33 100644
--- a/shared/tv/device_vendor.mk
+++ b/shared/tv/device_vendor.mk
@@ -91,3 +91,13 @@
CuttlefishTetheringOverlayGoogle \
CuttlefishWifiOverlayGoogle \
TvWifiOverlayGoogle
+
+# OEM Key:
+# ATV00 - Schema identifier.
+# 0 - Voice remote not included.
+# 000 - Not a panel TV.
+# 24 - Year of production.
+# CUTTLEFISH - Custom OEM key for future use.
+# EMU - Last 3 char for custom targeting.
+PRODUCT_PRODUCT_PROPERTIES += \
+ ro.oem.key1=ATV00000024CUTTLEFISHEMU
diff --git a/system_image/Android.bp b/system_image/Android.bp
index e4295da..83dc891 100644
--- a/system_image/Android.bp
+++ b/system_image/Android.bp
@@ -443,6 +443,7 @@
"printflags", // base_system
"privapp-permissions-platform.xml", // base_system
"prng_seeder", // base_system
+ "public.libraries.android.txt",
"recovery-persist", // base_system
"recovery-refresh", // generic_system
"requestsync", // media_system
@@ -550,6 +551,7 @@
"BlockedNumberProvider", // handheld_system
"BluetoothMidiService", // handheld_system
"BookmarkProvider", // handheld_system
+ "build_flag_system", // base_system
"BuiltInPrintService", // handheld_system
"CalendarProvider", // handheld_system
"CallLogBackup", // telephony_system
diff --git a/tools/create_base_image_gce.sh b/tools/create_base_image_gce.sh
index ba189cd..7073c83 100755
--- a/tools/create_base_image_gce.sh
+++ b/tools/create_base_image_gce.sh
@@ -37,6 +37,19 @@
# Stuff we need to get build support
sudo apt install -y debhelper ubuntu-dev-tools equivs "${extra_packages[@]}"
+function install_bazel() {
+ # From https://bazel.build/install/ubuntu
+ echo "Installing bazel"
+ sudo apt install apt-transport-https curl gnupg -y
+ curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg
+ sudo mv bazel-archive-keyring.gpg /usr/share/keyrings
+ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
+ # bazel needs the zip command to gather test outputs but doesn't depend on it
+ sudo apt-get update && sudo apt-get install -y bazel zip unzip
+}
+
+install_bazel
+
# Resize
sudo apt install -y cloud-utils
sudo apt install -y cloud-guest-utils
@@ -94,7 +107,7 @@
sudo chroot /mnt/image /usr/bin/apt update
sudo chroot /mnt/image /usr/bin/apt install -y "${tmp_debs[@]}"
# install tools dependencies
-sudo chroot /mnt/image /usr/bin/apt install -y openjdk-17-jre
+sudo chroot /mnt/image /usr/bin/apt install -y openjdk-21-jre
sudo chroot /mnt/image /usr/bin/apt install -y unzip bzip2 lzop
sudo chroot /mnt/image /usr/bin/apt install -y aapt
sudo chroot /mnt/image /usr/bin/apt install -y screen # needed by tradefed
diff --git a/tools/launch_cvd_arm64_server_docker.sh b/tools/launch_cvd_arm64_server_docker.sh
index ac1a939..d3fcceb 100755
--- a/tools/launch_cvd_arm64_server_docker.sh
+++ b/tools/launch_cvd_arm64_server_docker.sh
@@ -18,9 +18,10 @@
color_yellow="\033[0;33m"
# validate number of arguments
-if [ "$#" -lt 1 ] || [ "$#" -gt 3 ]; then
- echo "This script requires 1 mandatory and 2 optional parameters,"
- echo "server address and optionally cvd instances per docker, and number of docker instances to invoke"
+if [ "$#" -lt 1 ] || [ "$#" -gt 4 ]; then
+ echo "This script requires 1 mandatory and 3 optional parameters,"
+ echo "server address and optionally cvd instances per docker, and number of " \
+ "docker instances to invoke, and vendor_boot image to replace."
exit 1
fi
@@ -28,6 +29,7 @@
# $1: ARM server address
# $2: CVD Instance number per docker (Optional, default is 1)
# $3: Docker Instance number (Optional, default is 1)
+# $4: Vendor Boot Image path (Optional, default is "")
server=$1
if [ "$#" -lt 2 ]; then
@@ -42,6 +44,12 @@
num_dockers=$3
fi
+if [ "$#" -lt 4 ]; then
+ vendor_boot_image=""
+else
+ vendor_boot_image=$4
+fi
+
# set img_dir and cvd_host_tool_dir
img_dir=${ANDROID_PRODUCT_OUT:-$PWD}
cvd_host_tool_dir=${ANDROID_HOST_OUT:+"$ANDROID_HOST_OUT/../linux_musl-arm64"}
@@ -58,6 +66,10 @@
cvd_home_files=($(rsync -rzan --recursive $img_dir/bootloader --out-format="%n" $img_dir/*.img $server:~/$cvd_home_dir --info=name2 | awk '{print $1}'))
fi
+if [[ $vendor_boot_image != "" ]]; then
+ scp $vendor_boot_image $server:~/$cvd_home_dir/vendor_boot.img
+fi
+
# upload cvd-host_package.tar.gz into ARM server
temp_dir=/tmp/cvd_dist
rm -rf $temp_dir
diff --git a/vsoc_arm64_only/slim/aosp_cf.mk b/vsoc_arm64_only/slim/aosp_cf.mk
index 821b79e..1b9ab17 100644
--- a/vsoc_arm64_only/slim/aosp_cf.mk
+++ b/vsoc_arm64_only/slim/aosp_cf.mk
@@ -37,7 +37,6 @@
#
# All components inherited here go to vendor image
#
-LOCAL_PREFER_VENDOR_APEX := true
$(call inherit-product, device/google/cuttlefish/shared/slim/device_vendor.mk)
#
diff --git a/vsoc_riscv64/phone/aosp_cf.mk b/vsoc_riscv64/phone/aosp_cf.mk
index b5af1b9..668ea09 100644
--- a/vsoc_riscv64/phone/aosp_cf.mk
+++ b/vsoc_riscv64/phone/aosp_cf.mk
@@ -36,7 +36,6 @@
#
# All components inherited here go to vendor image
#
-LOCAL_PREFER_VENDOR_APEX := true
LOCAL_ENABLE_WIDEVINE := false
$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
diff --git a/vsoc_riscv64/slim/aosp_cf.mk b/vsoc_riscv64/slim/aosp_cf.mk
index ce71274..285317a 100644
--- a/vsoc_riscv64/slim/aosp_cf.mk
+++ b/vsoc_riscv64/slim/aosp_cf.mk
@@ -37,7 +37,6 @@
#
# All components inherited here go to vendor image
#
-LOCAL_PREFER_VENDOR_APEX := true
LOCAL_ENABLE_WIDEVINE := false
$(call inherit-product, device/google/cuttlefish/shared/slim/device_vendor.mk)
diff --git a/vsoc_x86_64/phone/aosp_cf.mk b/vsoc_x86_64/phone/aosp_cf.mk
index 41d7d29..a101d68 100644
--- a/vsoc_x86_64/phone/aosp_cf.mk
+++ b/vsoc_x86_64/phone/aosp_cf.mk
@@ -36,7 +36,6 @@
#
# All components inherited here go to vendor image
#
-LOCAL_PREFER_VENDOR_APEX := true
$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
# Nested virtualization support
diff --git a/vsoc_x86_64_only/slim/aosp_cf.mk b/vsoc_x86_64_only/slim/aosp_cf.mk
index 47b94c2..b38e918 100644
--- a/vsoc_x86_64_only/slim/aosp_cf.mk
+++ b/vsoc_x86_64_only/slim/aosp_cf.mk
@@ -37,7 +37,6 @@
#
# All components inherited here go to vendor image
#
-LOCAL_PREFER_VENDOR_APEX := true
$(call inherit-product, device/google/cuttlefish/shared/slim/device_vendor.mk)
#